工厂模式

来源:互联网 发布:Laymine java 编辑:程序博客网 时间:2024/06/06 08:27

一.案例

到披萨店(pizzaStore)买披萨(pizza),由于pizza有多种口味,且有部分操作(烘焙,切块,装盒)是一样的,所以抽象pizza类

1.抽象pizza类

public abstract class Pizza {private String name;// 每种pizza都有名称private String sauce;// 每种pizza酱料// 准备工作public void prepare () {System.out.println("准备材料:" + name + ", " + sauce);}// 烘焙public void bake () {System.out.println("烘焙");}// 切块public void cut () {System.out.println("切成8块");}// 装盒public void box () {System.out.println("装盒");}}

2.A口味的pizza

public class APizza extends Pizza {public APizza () {name = "A口味pizza";sauce = "A口味酱料";}}

3.B口味的pizza

public class BPizza extends Pizza {public BPizza () {name = "B口味pizza";sauce = "B口味酱料";}}


二.简单工厂

简单工厂其实不是一个设计模式,反而像是一种编程习惯

客户只需要到pizza商店去买pizza, 不需要关心pizza是怎么制作的,制作交给pizza工厂完成

1.pizza工厂:根据客户的选择条件动态实例化相关的类

public class PizzaFactory {public static Pizza createPizza (String pizzaType) {if ("A".equals(pizzaType)) {return new APizza();} else if ("B".equals(pizzaType)) {return new BPizza();} else {return null;}}}

2.pizza商店

public class PizzaStore {// 客户买pizzaType口味的pizzapublic Pizza buy (String pizzaType) {// 工厂负责创建pizzaPizza pizza = PizzaFactory.createPizza(pizzaType);pizza.bake();pizza.cut();pizza.box();}}

3.类图


4.优点

工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖

5.缺点

违反开放封闭原则 - 对扩展开放,对修改封闭。如果将来需要添加一个C口味的CPizza,那么,就必须在简单工厂类中添加相应的判断语句!另外,在简单工厂类中利用了if-else语句,这对程序的扩展本身就不不利。


三.工厂方法模式

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

1.案例变化

由于之前披萨店只在北京有一家,现在想在武汉和深圳各开一家,但由于地域的差异,每家分店的需要提供不同口味的pizza, 这就受到了开店地点和该区域pizza店口味的影响

给pizza店使用的框架 - 有个做法可以让pizza制作活动局限于PizzaStore类,但同时又能让各分店可以自由制作该区域口味的pizza:把PizzaFactory中的createPizza()方法放到PizzaStore中,不过要把它设置为“抽象方法”,然后为每个区域口味创建一个PizzaStore的子类

2.区域口味pizaa类

/** * 北京A口味的pizza * */public class BJAPizza extends Pizza{public BJPizza () {name = "北京A口味";sauce = "北京A口味";}}
/** * 北京B口味的pizza * */public class BJBPizza extends Pizza{public BJBPizza () {name = "北京B口味";sauce = "北京B口味";}}
/** * 武汉C口味的pizza * */public class WHCPizza extends Pizza{public WHCPizza () {name = "武汉C口味";sauce = "武汉C口味";}}
/** * 武汉D口味的pizza * */public class WHDPizza extends Pizza{public WHDPizza () {name = "武汉D口味";sauce = "武汉D口味";}}

3.抽象PizzaStore类

当buy()中调用createPizza()时,某个pizza店子类将负责创建pizza,做哪种口味的由具体的pizza店决定(如北京分店、武汉分店)

不过不是分店实时做出这样的决定,从buy()的角度看,如果选择在武汉分店买pizza,就由武汉分店(WHPizzaStore)绝定,严格来说,并非由分店实际做“决定”,而是由“顾客”决定到哪一家分店才决定了pizza的口味

/** * pizza店超类, 让各区域pizza店都继承这个类 * 每个子类各自决定制作什么口味的pizza * */public abstract PizzaStore () {/** * 每个子类都会覆盖本方法,同时使用本方法 * */public abstract Pizza createPizza (String pizzaType);/** * 客户到店买pizzaType口味的pizza * buy()并不知道哪些具体类参与了,这就是解耦 * */public Pizza buy (String pizzaType) {Pizza pizza = createPizza(pizzaType);pizza.bake();pizza.cut();pizza.box();}}

4.分店子类:由分店绝对各自的口味

让我们在北京和武汉各开一家分店吧,分店继承了PizzaStore类,免费获取了所有功能(烘烤、切块、装盒),分店只需实现createPizza()方法,制作自己口味的pizza即可

/** * 北京分店:有北京A口味、北京B口味pizza * */public class BJPizzaStore extends PizzaStore {public Pizza createPizza (String pizzaType) {if ("BJA".equals(pizzaType)) {return new BJAPizza();} else if ("BJB".equals(pizzaType)) {return new BJBPizza();} else {return null;}}}

/** * 武汉分店:有武汉C口味、武汉D口味pizza * */public class WHPizzaStore extends PizzaStore {public Pizza createPizza (String pizzaType) {if ("WHC".equals(pizzaType)) {return new WHCPizza();} else if ("WHD".equals(pizzaType)) {return new WHDPizza();} else {return null;}}}

5.利用工厂方法订购pizza

如:小明喜欢武汉分店的D口味的pizza

public class Test {public Static void main(String[] args){// buy()方法依赖于创建的具体类WHPizzaStorePizzaStore store = new WHPizzaStore();// 调用具体类WHPizzaStore重新的方法createPizza()store.buy("WHD");System.out.println("购买成功");}}

6.类图

工厂方法模式四个要素:

  • 工厂接口。工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品。在实际编程中,有时候也会使用一个抽象类来作为与调用者交互的接口,其本质上是一样的。
  • 工厂实现。在编程中,工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现
  • 产品接口。产品接口的主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性。同样,产品接口也可以用抽象类来代替,但要注意最好不要违反里氏替换原则
  • 产品实现。实现产品接口的具体类,决定了产品在客户端中的具体行为。

7.优点

a.简单工厂的进一步抽象和推广。它遵循了“开放—封闭”原则。

b.扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。

c. 屏蔽产品的具体实现,调用者只关心产品的接口。

8.缺点

每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

9.注意

作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

三.简单工厂和工厂方法模式的差异

工厂方法模式的子类(BJPizzaStore)看起来很像简单工厂,简单工厂把全部的事情在一个地方都处理完了,而工厂方法模式却是创建了一个框架,让子类决定要如何实现。比如:在工厂方法模式中,buy()方法提供了一般的框架,以便创建pizza,buy()方法依赖工厂方法创建具体类(先要实例化BJPizzaStore或WHPizzaStore),在制作出对应口味的pizza(具体类重写的createPizza()方法)。

简单工厂的做法:将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品


四.抽象工厂模式

工厂方法模式:一个抽象产品类,可以派生出多个具体产品类。   
                   一个抽象工厂类,可以派生出多个具体工厂类。 
               每个具体工厂类只能创建一个具体产品类的实例。 
抽象工厂模式:多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。 
                一个抽象工厂类,可以派生出多个具体工厂类。 
                 每个具体工厂类可以创建多个具体产品类的实例。 
            区别:工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
                工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。

抽像工厂优缺:
      优点:易于交换产品系列,例如Access和SQLServer数据库之间切换。
  缺点:例如增加一个机箱产品,不仅需要添加三个类“机箱类,微软机箱,惠普机箱”,还要修改惠普工厂,微软工厂支持制造机箱。而添加一个联想工厂的时候,只需要添加三个类,使用联想工厂还是要修改客户端代码的。

0 0
原创粉丝点击