工厂模式(Factory Pattern)定义:

  定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

  针对实现编程,但是当我们每次使用new时候,不正是在针对实现编程吗?是的,当使用“new”时,你的确实在实例化一个具体类,所以用的确实是实现,而不是接口。代码绑定这具体类会导致代码更脆弱,更缺乏弹性。

  Duck duck                          =                           new GreenDuck();

  使用接口让代码具有弹性                                 但还是得建立具体类的实例

  但我们总是要用new来创建对象吧。是的,在技术上,new没有错,毕竟这是Java基础部分。真正的犯人是我们的老朋友 “改变”,以及它是如何影响new的使用的。

看下面的代码:

 /*当有一群相关的具体类时,通常会写出这样的代码*/
Duck duck; if(picnic){
duck = new GreenDuck();
}else if(hunting){
duck = new DecoyDuck();
}else if(inBathTub){
duck = new RubberDuck();
}...//还有更多的实现类,在运行程序时,要通过判断,来确定创建哪个对象

  针对接口编程,可以隔离掉以后系统可能发生的一大堆改变。如果代码是针对接口编程而写,那么通过多态,它可以与任何新类实现该接口。但是,当代码使用大量的具体类时,等于是自找麻烦,因为一旦加入新的具体类,就必须改变代码。也就是说,你的代码并非 “对修改关闭”。想用新的具体类型来扩展代码,必须重新打开它。所以,遇到问题时候,就应该回到OO设计原则去寻找线索。别忘了,我们的第一个原则用来处理改变,并帮助我们 “找出会变化的方面,把它们从不变的部分分离出来”

举例:

  有一家比萨店,定制比萨的方法如下:

 Pizza orderPizza(String type){//这只是类中一个方法,将想要定制的比萨的type类型传入,就会制作出相应的比萨
Pizza pizza; if(type.equals("cheese")){//根据比萨的type类型,实例化正确的具体类,然后将其赋值给pizza实例变量。
pizza = new CheesePizza();//请注意,这里的任何比萨都必须实现Pizza接口
}else if(type.equals("greek"){
pizza = new GreekPizza();
}else if(type.equals("pepperoni"){
pizza = new PepperoniPizza();
} pizza.prepare();//一旦知道要制作什么类型的比萨,那么我们将要进行加工
pizza.bake();//这四个方法,分别是制作比萨的四个步骤
pizza.cut();
pizza.box(); return pizza;
}

orderPizza

正如上面所说,我们要制作新的比萨具体类或者删除现有的比萨具体类,都需要打开orderPizza()方法所在的类,来添加或删除里面的实例化。

我们要做的是,找出会变化的方面,把它们从不变的部分分离出来,现在我们将判断制作比萨类型部分从orderPizza()方法中分离出来:

 Pizza orderPizza(String type){//这只是类中一个方法,将想要定制的比萨的type类型传入,就会制作出相应的比萨
Pizza pizza; //原先实例化比萨的部分被分离出去 pizza.prepare();//一旦知道要制作什么类型的比萨,那么我们将要进行加工
pizza.bake();//这四个方法,分别是制作比萨的四个步骤
pizza.cut();
pizza.box(); return pizza;
}

orderPizza

 public class SimplePizzaFactory{
public Pizza createPizza(String type){
Pizza pizza = null; if(type.equals("cheese")){//根据比萨的type类型,实例化正确的具体类,然后将其赋值给pizza实例变量。
pizza = new CheesePizza();//请注意,这里的任何比萨都必须实现Pizza接口
}else if(type.equals("pepperoni"){//删除了一些比萨,又增加了一些比萨
pizza = new PepperoniPizza();
}else if(type.equals("clam"){
pizza = new ClamPizza();
}else if(type.equals("veggie"){
pizza = new VeggiePizza();
} return pizza;
}
}

SimplePizzaFactory

  从上面代码可以看出,我们将orderPizza()方法中实例化比萨的部分分离出来,单独放入了SimplePizzaFactory类中。

  那么,关于new的问题还是没有解决,我们还是针对实现编程,只是把针对实现编程的部分搬到了另一个对象中。问题还是存在,没错,确实存在。但是我们已经做到最小化改变代码(以我们现在所学的知识,还不足以脱离new来实例化对象,所以肯定要针对实现编程。若不能避免,那就做到最好!),若以后要修改创建比萨实例部分,就只要打开SimplePizzaFactory类就可以修改。

  现在我们将PizzaStore(比萨店)类实现:

 public class PizzaStore{
SimplePizzaFactory factory;//比萨工厂对象 public PizzaStore(SimplePizzaFactory factory){//在构造器中,需要一个工厂对象作为参数
this.factory = factory;
} public Pizza orderPizza(String type){
Pizza pizza; pizza = factory.createPizza(type);//将实例化比萨对象的责任交给工厂对象 pizza.prepare();//一旦知道要制作什么类型的比萨,那么我们将要进行加工
pizza.bake();//这四个方法,分别是制作比萨的四个步骤
pizza.cut();
pizza.box(); return pizza;
}
}

PizzaStore

上面的就是简单工厂模式,这只是小本生意的开始。我们只开了一家比萨店,现在我们的比萨店出名了,要开跨地区连锁店,规定每个地区开一家。我们做的比萨要符合当地人的口味。于是各个地区的比萨口味又不一样。

  不多说先把Pizza抽象类实现了:

 import java.util.ArrayList;

 public abstract class Pizza{
String name;//比萨名字
String dough;//面团
String sauce;//酱
ArrayList toppings = new ArrayList();//配料列表 void prepare(){//准备做比萨方法
System.out.println("Preparing " + name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings: "); for(int i = 0; i < toppings.size(); i++){
System.out.println(" " + toppings.get(i));
}
} void bake(){//烘焙方法
System.out.println("Bake for 25 minutes at 350");
} void cut(){//切块方法
System.out.println("Cutting the pizza into diagonal slices");
} void box(){//装盒方法
System.out.println("Place pizza in official PizzaStore box");
} public String getName(){//获取名称方法
return name;
}
}

Pizza

  然后根据各地区做出不同的Pizza:

 public class NYStyleCheesePizza extends Pizza{//NewYork比萨
public NYStyleCheesePizza(){
name = "NY Style Sauce and Cheese Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce"; toppings.add("Grated Reggiano Cheese");
}
}

NYStyleCheesePizza

 public class ChicagoStyleCheesePizza extends Pizza{//Chicago比萨
public ChicagoStyleCheesePizza(){
name = "Chicago Style Deep Dish Cheese Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce"; toppings.add("Shredded Mozzarella Cheese");
} void cut(){
System.out.println("Cutting the pizza into square slices");
}
}

ChicagoStyleCheesePizza

  实现PizzaStore抽象类:

 public abstract class PizzaStore{//所有地区的PizzaStore都要继承该抽象类
public Pizza orderPizza(String type){//定制Pizza方法
Pizza pizza; pizza = createPizza(type);//创建Pizza实例 pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box(); return pizza;
} abstract Pizza createPizza(String type);//创建Pizza实例的方法由每个地区的PizzaStore子类来实现
}

PizzaStore

  每个地区开一个PizzaStore:

 public class NYPizzaStore extends PizzaStore{//NewYork店
Pizza createPizza(String item){
if(item.equals("cheese")){//可以制作出cheese口味的Pizza
return new NYStyleCheesePizza();
}else return null;//也可以制作出其他口味的Pizza,我就不实现了。
}
}

NYPizzaStore

 public class ChicagoPizzaStore extends PizzaStore{//Chicago店
Pizza createPizza(String item){
if(item.equals("cheese")){//可以制作出Cheese口味的Pizza
return new ChicagoStyleCheesePizza();
}else return null;//也可以制作出其他口味的Pizza,我就不实现了。
}
}

ChicagoPizzaStore

  测试类:

 public class PizzaTestDrive{

     public static void main(String args[]){
//先开店
PizzaStore nyStore = new NYPizzaStore();
PizzaStore chicagoStore = new ChicagoPizzaStore(); //NYPizzaStore店制作出cheese口味的Pizza
Pizza pizza = nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
//ChicagoPizzaStore店制作出cheese口味的Pizza
pizza = chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
}
}

PizzaTestDrive

编译运行结果:

  上面的就是工厂模式。

总结一下,有两个抽象类:

1.Pizza抽象类:这个抽象类是产品抽象类,换句话说就是工厂要制作出的产品。所有的Pizza子类都要继承自该Pizza抽象类。

2.PizzaStore抽象类:这个抽象类是工厂抽象类,这个抽象类中有一个createPizza()抽象方法,这个方法就是为了让子类去实现自己的产品类。这样一来,子类可以根据自己的情况,随心所欲的生产符合自己口味的产品。

再细细地品味一下工厂模式的定义:

  工厂模式定义了一个创建对象的接口(工厂抽象类),但由工厂子类决定要实例化哪一个类。工厂方法让类把实例化推迟到了工厂子类。

由工厂子类决定要实例化哪一个类,不要理解错误。并不是指模式允许子类本身在运行时做决定,而是指在编写工厂抽象类时,不需要知道实际创建的产品是哪一个。选择使用了哪个子类,自然就决定了实际创建的产品是什么。

这里温馨提醒一下:在设计模式中,所谓的 “实现一个接口” 并 “不一定” 表示 “写一个接口,并利用implements关键字来实现这个接口”。“实现一个接口” 泛指 “实现某个超类型(可以是类或接口)的某个方法” 。

4.Factory Pattern(工厂模式)的更多相关文章

  1. 设计模式(四) Factory Pattern工厂模式

    核心: 实例化对象,实现创建者和调用者的分离 简单工厂模式 工厂方法模式 抽象工厂模式 面对对象设计的基本原则: ocp(open closed principle) 开闭原则:一个软件的实体应当对拓 ...

  2. Factory Pattern(工厂模式)

    1.工厂模式简介 工厂模式,专门负责将大量有共同接口的类实例化(用来生产对象).其定义为定义一个用于创建对象的接口,让子类决定实例化那一个类.工厂方法使一个类的实例化延迟到其子类. 工厂模式拥有以下几 ...

  3. 工厂模式(factory pattern) ------创造型模式

    创建型模式 简单工厂模式的缺点是: 当我们引入新产品时,由于静态工厂方法通过所传入参数的不同来创建不同的产品,需要修改工厂类的方法,违反了“开闭原则”. 工厂模式提供了一个抽象工厂接口来声明抽象工厂方 ...

  4. 抽象工厂模式(abstract factory pattern)------创造型模式

    创建型模式:抽象工厂模式 引入概念: 1.产品等级结构:当抽象的产品由具体的工厂生产出不同的产品时,这些归属与同一类的抽象产品就构成了产品等级结构: 2.产品族:具体的工厂可以生产出来的不同产品就构成 ...

  5. 设计模式(一): abstract factory抽象工厂模式 -- 创建型模式

    1.定义 为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类. 2.适用场景 1.一个系统要独立于它的产品创建.组合和表示. 2.一个系统要由多个产品系列中的一个来配置. 3.当你要 ...

  6. 设计模式(四)The Factory Pattern 出厂模式

    一.简单工厂 定义:定义一个创建对象的接口,可是由其子类决定要实例化的对象是哪一个,工厂方法让类的实例化推迟到子类. 通俗的来讲就是由工厂方法确定一个框架.详细的实现由其子类来完毕. 与简单工厂相比, ...

  7. c++ 设计模式9 (Abstract Factory 抽象工厂模式)

    5.2 抽象工厂模式 动机:在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作:同时,由于需求的变化,往往存在更多系列对象的创建工作. 代码示例: 实现利用数据库的业务逻辑,支持多数据库(Sq ...

  8. Simple Factory 简单工厂模式(静态工厂)

    基本概念: 1) Simple Factory模式属于创建型模式, 2) 简单工厂模式是由一个工厂(注意是一个!)对象决定创建出哪一种产品类的实例(例如你到肯德基说你要鸡腿,要薯条,要饮料还是,,,这 ...

  9. Simple Factory (简单工厂模式)

    简单工厂模式不是23种设计模式之一,简单工厂模式属于创建型模式, 又叫做静态工厂方法(Static Factory Method) 简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模 ...

  10. Java设计模式:Simple Factory(简单工厂)模式

    概念定义 简单工厂(Simple Factory)模式,又称静态工厂方法(Static Factory Method)模式,即定义一个工厂类,根据传入的不同参数创建不同的产品实例,这些实例对象具有共同 ...

随机推荐

  1. 利用App漏洞获利2800多万元,企业该如何避免类似事件?

    上个月,上海警方抓捕了一个利用网上银行漏洞非法获利的犯罪团伙,该团伙利用银行App漏洞非法获利2800多万元. 据悉,该团伙使用技术软件成倍放大定期存单金额,从而非法获利.理财邦的一篇文章分析了犯罪嫌 ...

  2. css居中小结

    从css入门就开始接触,无所不在的,一直备受争议的居中问题. css居中分为水平居中和垂直居中,水平居中方式也较为常见和统一,垂直居中的方法就千奇百怪了. 博客原文地址:Claiyre的个人博客 ht ...

  3. DevOps - CI - SVN

    SVN http://tortoisesvn.net/ 支持文档:http://tortoisesvn.net/support.html 在线TortoiseSVN 中文文档:http://torto ...

  4. centos7搭建kafka集群-第二篇

    好了,本篇开始部署kafka集群 Zookeeper集群搭建 注:Kafka集群是把状态保存在Zookeeper中的,首先要搭建Zookeeper集群(也可以用kafka自带的ZK,但不推荐) 1.软 ...

  5. 《Python编程从入门到实践》--- 学习过程笔记(3)列表

    一.用[](方括号)表示列表,用,(逗号)分隔其中的元素. >>> name=['limei', 'hanmeimei', 'xiaoming'] >>> prin ...

  6. [Leetcode]下一个更大元素II

    题目 给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素.数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地 ...

  7. 【sping揭秘】3、Spring容器中bean默认是保持一个实例

    Spring容器中bean默认是保持一个实例 这里做一个测试,基础代码 package cn.cutter.start.provider; import org.springframework.con ...

  8. Linux CPU实时监控工具

    注:ubuntu需要安装sysstat: sudo apt install sysstat [root@testDb ~]# mpstat 1 10    ---显示操作系统内核版本 以及硬件配置   ...

  9. Parallel Gradient Boosting Decision Trees

    本文转载自:链接 Highlights Three different methods for parallel gradient boosting decision trees. My algori ...

  10. npm 安装 cannot find module

    window7安装module出现 Connot find module 'xxx' 解决办法: 添加环境变量命名为:NODE_PATH 设置值为:%AppData%\npm\node_modules ...