内容简介:工厂模式的个人小结
工厂模式是一种常见的 设计模式 了。当我们实例化一个具体类时往往会第一时间想到用new。当子类需要被分成不同的情况去实例化时,我们一般想到的就是写一些if判断,而这种处理方式会给我们今后代码的维护带来很多麻烦。如何将实例化具体类的代码从应用中抽离,或者封装起来,使它们不会干扰应用的其他部分?
首先我们从披萨店的设计中看看工厂模式为什么需要出现?
假设你有一个披萨店,原来你要生产一个披萨代码你可能是这样写:
Pizza orderPizza(){ // 创建pizza Pizza pizza = new Pizza(); // 对披萨的加工 ... return pizza; }
但是,当你需要更多口味的披萨时,你可能会考虑将代码改写一下:
Pizza orderPizza(String type){ // 创建pizza Pizza pizza; if ("cheese".equals(type)) { pizza = new CheesePizza(); } else if ("greek".equals(type)) { pizza = new GreekPizza(); } // 对披萨的加工 ... return pizza; }
随着生意的发展,问题又来了。披萨的种类需求越来越多,需要新增或删除披萨的种类时往往需要去修改上面的代码。
让我们回到OO设计原则,看看怎么改动这段代码比较好,最基本的单一原则。将创建披萨的部分抽离出来,看成一个新对象,这个新对象只管如何创建对象。我们称这个对象为“工厂”。
简单工厂方法
简单工厂方法与其说是工厂模式的一种,更不如说它其实就是我们的一种编程习惯。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
public class SimplePizzaFactory { public Pizza createPizza(String type){ Pizza pizza = null; if ("cheese".equals(type)) { pizza = new CheesePizza(); } else if ("greek".equals(type)) { pizza = new GreekPizza(); } return pizza; } }
这样,我们的披萨店在生产披萨的时候代码就改写成这样了
public class PizzaStore { SimplePizzaFactory factory; public PizzaStore(SimplePizzaFactory factory){ this.factory = factory; } public Pizza orderPizza(String type){ Pizza pizza = factory.createPizza(type); return pizza; } public static void main(String args[]){ PizzaStore pizzaStore = new PizzaStore(new SimplePizzaFactory()); Pizza pizza = pizzaStore.orderPizza("cheese"); System.out.println(pizza.toString()); } }
简单工厂方法仅仅是遵守了单一原则,将创建对象的责任承担了下来,如果有新增披萨种类我们还是只能在createPizza方法中加判断条件,这还是违背了开闭原则(对扩展开放,对修改关闭)的。有没有解决办法?答案是有的,工厂方法模式出现了。
工厂方法模式
工厂类定义成了接口,而每新增的披萨类型,就增加该披萨类型对应工厂类的实现,这样工厂的设计就可以扩展了,而不必去修改原来的代码。工厂方法模式通过让子类决定该创建的对象是什么,把类的实例化推迟到子类,来达到将对象创建的过程封装的目的。根据这个思想,我们开两家专门卖纽约口味的和芝加哥口味披萨的分店,让他们分别为我们总店提供想要的披萨吧。
先把总店变成抽象类
public abstract class PizzaStore { abstract Pizza createPizza(String type); public Pizza orderPizza(String type){ Pizza pizza = createPizza(type); return pizza; } }
然后我们来开两家分店
芝加哥分店
public class ChicagoPizzaStore extends PizzaStore { @Override Pizza createPizza(String type) { if ("cheese".equals(type)) { return new ChicagoStyleCheesePizza(); } else{ return null; } } }
纽约分店
public class NYPizzaStore extends PizzaStore { @Override Pizza createPizza(String type) { if ("cheese".equals(type)) { return new NYStyleCheesePizza(); } else{ return null; } } }
披萨也要分口味
public class ChicagoStyleCheesePizza extends CheesePizza { @Override public String toString() { return super.toString()+" of Chicago"; } } public class NYStyleCheesePizza extends CheesePizza { @Override public String toString() { return super.toString()+" of NY"; } }
点个芝士披萨看看吧
public class PizzaTest { public static void main(String args[]){ PizzaStore nyStore = new NYPizzaStore(); Pizza pizza = nyStore.orderPizza("cheese"); System.out.println(pizza.toString()); PizzaStore chicagoStore = new ChicagoPizzaStore(); pizza = chicagoStore.orderPizza("cheese"); System.out.println(pizza.toString()); } }
执行结果截图如下:
抽象工厂模式
工厂方法模式能够封装具体类型的实例化,相当于说搭了一个框架,让子类决定要如何实现,说白了也是一些简单工厂方法的集合。我们在用的时候只需要关心是哪个店出来的披萨就好,不需要关心具体实现。但是还有一个我们不想看到的问题,当披萨的不同口味的分店越来越多时,同样会多很多新的类。披萨店依赖于所有的披萨对象,因为它直接创建这些披萨对象。对具体类的依赖过多这恰恰不遵守了OO设计原则的依赖倒置原则(要依赖抽象,不要依赖具体类)。依赖倒置原则,很抽象,暂时不用理会。披萨店原本依赖于很多具体的披萨对象,披萨的口味不一样也就是做法、原料有略微不同而已,现在这些不同口味的披萨我们都可以抽象成披萨,也就是说披萨店依赖于抽象出来的披萨(Pizza),至于具体的披萨对象,它们则依赖抽象出来的披萨(因为它们都实现了Pizza接口),这样一来依赖就倒置了。我们可以将我们的工厂拆分成四个角色:抽象的工厂和具体的工厂;抽象的产品和具体的产品。
下面看具体的一个例子吧
抽象出一个披萨类
public abstract class Pizza { String name; // 名称 String material; // 材料 String practice; // 做法 abstract void prepare(); public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "[name:"+name+";material:"+material +";practice:"+practice+"]"; } }
抽象出一个工厂接口,负责做披萨的材料和做法
public interface PizzaFactory { public String getMaterial(); public String getPractice(); }
纽约风味披萨的实现
public class NYPizzaFactory implements PizzaFactory { @Override public String getMaterial() { return "纽约的面粉"; } @Override public String getPractice() { return "纽约的做法"; } }
芝士披萨
public class CheesePizza extends Pizza { PizzaFactory factory; public CheesePizza(PizzaFactory factory){ this.factory = factory; } void prepare() { System.out.println(name+"准备中..."); material = factory.getMaterial(); practice = factory.getPractice(); } }
负责做纽约披萨的分店,总店的定义还是没变
public class NYPizzaStore extends PizzaStore { @Override protected Pizza createPizza(String type) { Pizza pizza = null; PizzaFactory factory = new NYPizzaFactory(); if ("cheese".equals(type)) { pizza = new CheesePizza(factory); pizza.setName("纽约口味的芝士披萨"); } return pizza; } }
准备待续,买个披萨吧
public class PizzaTest { public static void main(String args[]){ PizzaStore nyStore = new NYPizzaStore(); Pizza pizza = nyStore.orderPizza("cheese"); pizza.prepare(); System.out.println(pizza.toString()); } }
执行结果如图所示:
抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么。这样一来,客户就从具体的产品中被解耦。
无论是简单工厂方法,工厂方法模式,还是抽象工厂模式,它们的作用都是为了解耦,在平时工作的使用中根据需求灵活地使用,而不必拘束于只使用一种。
以上就是我对《Head First 设计模式》中关于工厂模式的一些理解及参考书上的例子自己写的一些例子。记录一下方便今后复习。详细代码见 Github
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 设计模式-简单工厂、工厂方法模式、抽象工厂模式
- 简单工厂模式、工厂模式、抽象工厂模式的解析-iOS
- Swift中的工厂方法和抽象工厂
- Java 设计模式之工厂方法模式与抽象工厂模式
- 设计模式-创建型模式-工厂模式(工厂三兄弟) TypeScript
- 设计模式之工厂模式(为什么很多人觉得工厂模式没有用)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。