设计模式之——工厂模式(A)
2014-11-13 19:27
155 查看
本文是在学习中的总结,欢迎转载但请注明出处:/article/1495226.html
昨天看完了工厂模式,觉得在开发的过程中好多地方都能够使用工厂模式,但是很多时候却都没有去使用。我觉得一方面可能是偷懒,懒得去思考,懒得去设计接口;另一方面可能是只为了眼前的需求,觉得开发的产品能使用就行,而不管其后续的维护以及更新。这两个方面长期下去,对自己的提升没有什么好处。其实我自己就是属于第二类,只为了眼前的需求而不去思考后续的维护和更新。可能是刚工作不久,没有那么好的技术,我想我会慢慢转变自己,能够写出漂亮的代码。闲话不多说了,下面分享工厂模式的一些学习总结。
我们一般创建对象都喜欢new一个,因为比较方便;但是我们在使用new的时候,是在实例化一个具体的类,代码绑定了具体的类会导致代码比较脆弱,缺乏弹性;当类发生变化时,涉及到该类的地方都必须修改代码,这样会导致代码一团糟。
假设我们有一家面包店BreadStore,刚开业的时候,只提供一种面包,当需要订购面包的时候,代码可能会这样写:
随着时间的推移,需求变大了,有的人想吃玉米面包,有的人想吃豆沙面包,还有的人想吃巧克力面包......,此时代码可能又变成这样了:
又过了一段时间,附近开了好多家面包店,竞争激烈,你发现竞争者的菜单中多了一些流行风味的面包,比如欧洲面包、荞麦面包,而最近玉米面包又卖的不好,我们决定将其从菜单上撤销,此时的代码又变成这样了:
我们可以看出,只要随着时间的改变,if...else...里面的需求总是在变化,当我们依赖了具体变化的类时,代码将变得特别难以维护,此时,我们应该考虑到抽象。另外,我们注意到,return上面的四行代码是不想改变的地方,其包含了面包的准备、烘烤、包装,这些流程多年都没有变化,此时可使用封装,将不变的部分封装起来。
首先,我们把创建Bread对象的代码从orderBread()方法中抽离出来,然后把该代码转移到另外一个新对象中,新对象只管如何创建面包。任何时候需要创建面包,就找它。我们也称该对象为“工厂”。这里,我们创建一个简单的面包工厂SimpleBreadFactory,而orderBread()就成为了该工厂的客户。当需要面包的时候,就叫面包工厂做一个出来。现在,orderBread()方法只关心从工厂得到一个面包,而此时的面包实现了抽象的Bread接口,而Bread接口提供了prepare()、bake()、cut()、box()方法来进行相应操作。抽象Bread和创建的简单工厂的代码如下:
现在,我们可以重新构造BreadStore了,我们要做的就是依靠工厂来为我们创建面包,代码如下:
在上面的代码中,我们为BreadStore加上了对简单面包工厂的引用;在BreadStore是构造器中需要传入一个工厂作为参数;在orderBread()方法中通过简单传入订单类型来使用工厂创建面包,在这里面我们把new操作符替换为工厂对象创建方法,不再使用具体实例化。
若干年后,面包店经营的不错,很多地方的消费者都希望面包店能够在当地有加盟店,此时,简单面包工厂已经不能满足需求了,加盟店都希望有适合当地需求的面包工厂,这样就产生了类似BJBreadFactory、TJBreadFactory、SHBreadFactory的面包工厂。
考虑到让面包***局限于BreadStore,同时又能够让加盟店仍然可以自由***该区的面包,这样就允许子类做决定了。我们将BreadStore抽象出来。
对于BreadStore的子类,每一个都会覆盖createBread()方法,同时又使用BreadStore中的orderBread()方法,其实也可将orderBread()声明为final,以防止被子类覆盖。这样,不同地区的加盟店都可以创建需要的面包了。
我们在武汉开一家新的面包店:
通过声明工厂方法 ,我们可以看出:原来是由一个对象负责所有具体类的实例化,现在我们对BreadStore做了一些调整,变成了由一群子类来负责实例化。
对于 abstract Product factoryMethod(String type)工厂方法:
(1)工厂方法是抽象的,所以需要依赖子类来处理对象的创建。
(2)工厂方法必须返回一个产品。在超类中定义的方法,通常会用到工厂方法的返回值。
(3)工厂方法将客户(超类中的代码,如orderBread()和实际创建具体产品的代码分离开来)。
最后,我们再来认识一下工厂方法模式:所有的工厂模式都是用来封装对象的创建,这样就减小了耦合。它是通过让子类来决定该创建的对象是什么,从而来达到将对象创建的过程封装的目的。下面两张图反映了创建者类和产品类之间的关系:
昨天看完了工厂模式,觉得在开发的过程中好多地方都能够使用工厂模式,但是很多时候却都没有去使用。我觉得一方面可能是偷懒,懒得去思考,懒得去设计接口;另一方面可能是只为了眼前的需求,觉得开发的产品能使用就行,而不管其后续的维护以及更新。这两个方面长期下去,对自己的提升没有什么好处。其实我自己就是属于第二类,只为了眼前的需求而不去思考后续的维护和更新。可能是刚工作不久,没有那么好的技术,我想我会慢慢转变自己,能够写出漂亮的代码。闲话不多说了,下面分享工厂模式的一些学习总结。
我们一般创建对象都喜欢new一个,因为比较方便;但是我们在使用new的时候,是在实例化一个具体的类,代码绑定了具体的类会导致代码比较脆弱,缺乏弹性;当类发生变化时,涉及到该类的地方都必须修改代码,这样会导致代码一团糟。
假设我们有一家面包店BreadStore,刚开业的时候,只提供一种面包,当需要订购面包的时候,代码可能会这样写:
Bread orderBread(){ Bread bread = new Bread(); bread.prepare(); bread.bake(); bread.cut(); bread.box(); return bread; }
随着时间的推移,需求变大了,有的人想吃玉米面包,有的人想吃豆沙面包,还有的人想吃巧克力面包......,此时代码可能又变成这样了:
Bread orderBread(String type){ Bread bread; if("corn".equals(type)){ bread = new CornBread(); } else if("beanpaste".equals(type)){ bread = new BeanpasteBread(); } else if("chocolate".equals(type)){ bread = new ChocolateBread(); } bread.prepare(); bread.bake(); bread.cut(); bread.box(); return bread; }
又过了一段时间,附近开了好多家面包店,竞争激烈,你发现竞争者的菜单中多了一些流行风味的面包,比如欧洲面包、荞麦面包,而最近玉米面包又卖的不好,我们决定将其从菜单上撤销,此时的代码又变成这样了:
Bread orderBread(String type){ Bread bread; if(<span style="color:#cc0000;">"corn".equals(type</span>)){ <span style="color:#ff0000;">bread = new CornBread()</span>; } else if("beanpaste".equals(type)){ bread = new BeanpasteBread(); } else if("chocolate".equals(type)){ bread = new ChocolateBread(); } <span style="color:#cc33cc;">else if("Europe".equals(type)</span>){ <span style="color:#cc33cc;">bread = new EuropeBread()</span>; } <span style="color:#cc33cc;">else if("Buckwheat".equals(type)</span>){ <span style="color:#cc33cc;">bread = new BuckwheatBread()</span>; } bread.prepare(); bread.bake(); bread.cut(); bread.box(); return bread; }
我们可以看出,只要随着时间的改变,if...else...里面的需求总是在变化,当我们依赖了具体变化的类时,代码将变得特别难以维护,此时,我们应该考虑到抽象。另外,我们注意到,return上面的四行代码是不想改变的地方,其包含了面包的准备、烘烤、包装,这些流程多年都没有变化,此时可使用封装,将不变的部分封装起来。
首先,我们把创建Bread对象的代码从orderBread()方法中抽离出来,然后把该代码转移到另外一个新对象中,新对象只管如何创建面包。任何时候需要创建面包,就找它。我们也称该对象为“工厂”。这里,我们创建一个简单的面包工厂SimpleBreadFactory,而orderBread()就成为了该工厂的客户。当需要面包的时候,就叫面包工厂做一个出来。现在,orderBread()方法只关心从工厂得到一个面包,而此时的面包实现了抽象的Bread接口,而Bread接口提供了prepare()、bake()、cut()、box()方法来进行相应操作。抽象Bread和创建的简单工厂的代码如下:
public abstract class Bread { void prepare(){ System.out.println("prepare for..."); } 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 class SimpleBreadFactory(){ public Bread() creatBread(String type){ Bread bread = null; if("corn".equals(type)){ bread = new CornBread(); } else if("beanpaste".equals(type)){ bread = new BeanpasteBread(); } else if("chocolate".equals(type)){ bread = new ChocolateBread(); } return bread; } }
现在,我们可以重新构造BreadStore了,我们要做的就是依靠工厂来为我们创建面包,代码如下:
public class BreadStore{ SimpleBreadFactory factory; public BreadStore(SimpleBreadFactory factory){ this.factory = factory; } public Bread orderBread(String type){ Bread bread; /**未抽象之前的Bread**/ bread = factory.creatBread(type); bread.prepare(); bread.bake(); bread.cut(); bread.box(); return bread; } }
在上面的代码中,我们为BreadStore加上了对简单面包工厂的引用;在BreadStore是构造器中需要传入一个工厂作为参数;在orderBread()方法中通过简单传入订单类型来使用工厂创建面包,在这里面我们把new操作符替换为工厂对象创建方法,不再使用具体实例化。
若干年后,面包店经营的不错,很多地方的消费者都希望面包店能够在当地有加盟店,此时,简单面包工厂已经不能满足需求了,加盟店都希望有适合当地需求的面包工厂,这样就产生了类似BJBreadFactory、TJBreadFactory、SHBreadFactory的面包工厂。
BJBreadFactory bjFactory = new BJBreadFactory(); BreadStore bjStore = new BreadStore(bjFactory); bjStore.orderBread("bjtaste"); TJBreadFactory tjFactory = new TJBreadFactory(); BreadStore tjStore = new BreadStore(tjFactory); tjStore.orderBread("bjtaste"); SHBreadFactory shFactory = new SHBreadFactory(); BreadStore shStore = new BreadStore(shFactory); shStore.orderBread("bjtaste");
考虑到让面包***局限于BreadStore,同时又能够让加盟店仍然可以自由***该区的面包,这样就允许子类做决定了。我们将BreadStore抽象出来。
public abstract class BreadStore{ abstract Bread creatBread(String type); public Bread orderBread(String type){ Bread bread; /**未抽象之前的Bread**/ bread = factory.creatBread(type); bread.prepare(); bread.bake(); bread.cut(); bread.box(); return bread; } }
对于BreadStore的子类,每一个都会覆盖createBread()方法,同时又使用BreadStore中的orderBread()方法,其实也可将orderBread()声明为final,以防止被子类覆盖。这样,不同地区的加盟店都可以创建需要的面包了。
我们在武汉开一家新的面包店:
public class WHBreadStore extends BreadStore{ Bread creatBread(String item){ if("corn".equals(item)){ bread = new WHCornBread(); } else if("beanpaste".equals(item)){ bread = new WHBeanpasteBread(); } else if("chocolate".equals(item)){ bread = new WHChocolateBread(); } else return null; } }
通过声明工厂方法 ,我们可以看出:原来是由一个对象负责所有具体类的实例化,现在我们对BreadStore做了一些调整,变成了由一群子类来负责实例化。
对于 abstract Product factoryMethod(String type)工厂方法:
(1)工厂方法是抽象的,所以需要依赖子类来处理对象的创建。
(2)工厂方法必须返回一个产品。在超类中定义的方法,通常会用到工厂方法的返回值。
(3)工厂方法将客户(超类中的代码,如orderBread()和实际创建具体产品的代码分离开来)。
最后,我们再来认识一下工厂方法模式:所有的工厂模式都是用来封装对象的创建,这样就减小了耦合。它是通过让子类来决定该创建的对象是什么,从而来达到将对象创建的过程封装的目的。下面两张图反映了创建者类和产品类之间的关系:
相关文章推荐
- 设计模式—工厂模式
- C++设计模式之一 工厂模式(简单工厂、工厂和抽象工厂)
- C++设计模式之一 工厂模式(简单工厂、工厂和抽象工厂)
- C++设计模式之一 工厂模式(简单工厂、工厂和抽象工厂)
- 重构 - 理解设计模式的捷径(4 设计模式的引入 - 工厂模式)
- 设计模式之3个工厂模式
- [Gof设计模式]简单工厂模式和工厂模式的C++实现
- C++设计模式之一 工厂模式(简单工厂、工厂和抽象工厂)
- 设计模式 简单工厂模式和工厂模式的区别
- 设计模式随笔-从“有病”说起(工厂模式前传)
- 设计模式学习(二)简单工厂模式-工厂模式-抽象工厂模式
- Java 设计模式-工厂模式
- 设计模式-工厂模式(手工作坊到工业化的转变 c#实现)
- 设计模式之——工厂模式
- 设计模式(1)-工厂模式(Factory)
- 设计模式-工厂模式(手工作坊到工业化的转变 c#实现)
- (转帖) 设计模式随笔-从“有病”说起(工厂模式前传)
- 魔兽争霸之PHP设计模式-工厂模式[Factory]
- [转]C++设计模式之一 工厂模式(简单工厂、工厂和抽象工厂)
- 设计模式-工厂模式(手工作坊到工业化的转变 c#实现)