首页 > 代码库 > 设计模式——工厂模式
设计模式——工厂模式
工厂模式有两种类型:工厂方法模式和抽象工厂模式
工厂方法模式定义:定义了一个创建对象的接口(这里的接口并不是单单是指java中的interface),但由子类决定实例化的类是哪一个。工厂方法让类把实例化推迟到子类中。
抽象工厂模式定义:提供一个接口(这里的接口并不是单单是指java中的interface),用于创建相关或依赖对象的家族,而不需要明确指定具体的类。
不管工厂模式的形式是哪一种,我们要清楚的知道工厂模式的作用,工厂模式是用来封装对象的创建的!也就是说工厂模式用来管理创建对象的,其他的一概和工厂模式无关。
通过封装对象的创建,就可以达到松耦合的目的,因为滥用new关键字会将多个对象绑定起来,从而耦合在一起,而工厂模式就是要将这些耦合解开,然后以最小的耦合来达到相同的目的。
比如说:现在要在多个村庄之间组建电网,第一种方案就是“图方便原则”,我们忽略掉村与村之间的界限,只要两个住户之间相隔近,不管他俩是不是一个村,我们都将这两家住户连在同一根电线上,当扩展到成百上千的住户的时候,我们可以想象,这时的电路网会错综复杂,难以管理,当需要更改电网的时候,也是牵一发而动全身。第二个方案是将住户以村为单位,或者更小的,我们以生产队为单位,一个生产队里面的住户采取“图方便原则”,而生产队之间用一根电线连接起来,这样生产队内部的调整不会影响到其他的生产队,也便于管理,这样就以最小的耦合来达到了相同的目的。实际上这里的每一个电线连接处我们都可以将其视为一个new关键字。
当然上面的例子只是宽泛的类比了一下工厂模式,例子不一定准确,下面通过一个真正的实例来介绍工厂模式中的工厂方法模式:
- 需求说明
- 系统设计
需要使用new的地方,就是对象之间关联的地方,也就是耦合发生的地方,虽然完全消除对象之间的关联是一件不可能的事情,但是我们可以在保证需求的前提下,尽量的减少耦合,或者将耦合全部集中到一个易于管理的地方。
对于 本例子来说,对象之间的关联在于:①具体的店铺和抽象店铺的关联;②具体面食与抽象面食之间的关联。我们可以将抽象店铺与具体店铺之间用一个new关键字来关联,同时将同一类店铺中所有的面食种类全部封装在店铺内部,这样每个店铺就可以管理自己的面食,店铺与店铺之间不相关联。
- 系统实现
1 面食抽象类: 2 /** 3 * 声明为抽象方法,不能直接new,实例化交给工厂来做 4 * @author Apache_xiaochao 5 * 6 */ 7 public abstract class Noodle { 8 9 private String name; // 名称10 private String dough; // 面团11 private List<String> spices; // 调料12 13 /**14 * 准备食材15 */16 public void prepare() {17 System.out.println(18 "正在准备食材,面食名称:" + this.getName() +19 " 面团名称:" + this.getDough() +20 " 调料:" + spices.toString());21 }22 23 /**24 * 烧水25 */26 public void boilWater() {27 System.out.println("正在烧水...");28 }29 30 /**31 * 煮面32 */33 public void cook() {34 System.out.println("正在煮面...");35 }36 37 /**38 * 装盘39 */40 public void sabot() {41 System.out.println("正在装盘...");42 } 43 //余下的get和set方法,省略...44 }
1 面食店抽象类: 2 /** 3 * 面食店抽象类,所有的面食店都需要继承这个抽象类 4 * @author Apache_xiaochao 5 * 6 */ 7 public abstract class NoodleStore { 8 9 /**10 * 根据用户需求制作相应的面食11 * @param type12 * @return13 */14 public Noodle orderNoodle(String type){15 Noodle noodle = null;16 if(type != null){17 noodle = createNoodle(type);18 noodle.prepare();19 noodle.boilWater();20 noodle.cook();21 noodle.sabot();22 }23 return noodle;24 }25 26 /**27 * 工厂方法 ,将new全部集中到这个方法里面去,然后将new延迟到子类中实现28 * @param type29 * @return30 */31 protected abstract Noodle createNoodle(String type); //这里是核心,工厂方法就在这32 //上面定义了一个抽象的工厂方法,也可以不是抽象的,我们可以在这里定义一个默认的工厂。33 //这里讲所有的new全部集中到工厂方法中进行管理,每个子类都可以在该方法中管理自己的对象34 //这里采用的是“参数化工厂方法”,可以根据传递的参数而创建不同的对象,然而工厂常常只产生一种对象,因此不需要参数化35 36 }
1 具体的面食店,以山西面食馆为例: 2 /** 3 * 山西面食馆 4 * 5 * @author Apache_xiaochao 6 * 7 */ 8 public class ShanXiNoodleStore extends NoodleStore { 9 10 @Override11 protected Noodle createNoodle(String type) {12 Noodle noodle = null;13 if (type != null) {14 if ("saozi".equalsIgnoreCase(type)) {15 noodle = new SXSaoziNoodle();16 } else if ("liujian".equalsIgnoreCase(type)) {17 noodle = new SXLiujianNoodle();18 }19 }20 return noodle;21 }22 23 }24 在这个具体的面食店里面,我们使用了很多的new,这些new可以轻松被管理,如果以后这家店希望添加新的面食,或者减少不受欢迎的面食,改起来就方便很多。
整个架构中代码执行过程说明:
- 我们先在某个地方开一家山西面食馆:NoodleStore noodleStore = new ShanXiNoodleStore(); //店铺开起来了
- 假设现在有一位顾客走进我们新开的面食馆,点了一份臊子面:noodleStore.orderNoodle("saozi"); //来生意啦
- 点完餐之后,系统开始运行,步骤如下:
因为是在山西面食馆里面点餐,所以是山西面食馆里面的系统在为我们服务,当指定面食类型之后,系统就会为我们准备后相应的食材,然后开始制作面食(这些基本上都是大同小异,如果有不同的地方,可以覆盖父类中的相关方法)
对于工厂方法的总结:
工厂模式都是用来封装对象的创建的。工厂方法模式属于工厂模式,当然也是为封装对象创建而服务的,由上面的例子我们可以看,所有对象的创建都被封装到工厂方法之中,而且这个方法的实现,并没有在NoodleStore这个类中,而是在NoodleStore的子类中,因为子类更加清楚要做什么,这样就在一定程度上达到了松耦合的目的,并且让代码更加清晰、灵活、易于扩展。
再次给出工厂方法模式的定义:定义一个创建对象的接口(这里的接口就是指工厂方法),但由子类决定要实例化的类是哪一个(工厂方法的实现在子类中)。工厂方法让类把实例化推迟到子类。
接下来我们仍然使用这个例子来讲解抽象工厂模式:
- 需求说明
- 系统设计
这一次我们选用抽象工厂,既然也属于工厂模式,那么它的作用还是用来封装对象的创建。(下图为相应UML图,不过已经没有什么可看性了,太复杂)
- 系统实现
1 抽象工厂接口: 2 /** 3 * 抽象工厂 4 * @author Apache_xiaochao 5 * 6 */ 7 public interface NoodleIngredientFactory { 8 9 public abstract Dough orderDough(); //提供面团10 public abstract Shallot orderShallot(); //提供小葱11 public abstract Chili orderChili(); //提供辣椒12 public abstract Egg orderEgg(); //提供鸡蛋13 14 }15 抽象工厂中定义了各种各样食材的供应方法,这些都返回了相应的食材对象,肯定需要用到很多new关键字,这里我们用抽象工厂将它们封装起来。
1 具体工厂的实现(以东北食材供应工厂为例): 2 /** 3 * 东北原料工厂,这个工厂为东北全境的东北面食馆提供食材 4 * @author Apache_xiaochao 5 * 6 */ 7 public class DongBeiIngredientFactory implements NoodleIngredientFactory { 8 9 @Override10 public Dough orderDough() {11 Dough dough = new Dough();12 dough.setName("黑龙江优质小麦");13 return dough;14 }15 16 @Override17 public Shallot orderShallot() {18 Shallot shallot = new Shallot();19 shallot.setName("山东大葱");20 return shallot;21 }22 23 @Override24 public Chili orderChili() {25 Chili chili = new Chili();26 chili.setName("西北红辣椒");27 return chili;28 }29 30 @Override31 public Egg orderEgg() {32 Egg egg = new Egg();33 egg.setName("农家土鸡蛋");34 return egg;35 }36 37 }
1 具体面食馆的实现(以东北面食馆为例): 2 /** 3 * 东北面食馆 4 * 5 * @author Apache_xiaochao 6 * 7 */ 8 public class DongBeiNoodleStore extends NoodleStore { 9 10 private NoodleIngredientFactory nif;11 12 //在构造方法中指定由哪个食材工厂来提供食材13 public DongBeiNoodleStore() {14 this.nif = new DongBeiIngredientFactory();15 }16 17 @Override18 protected Noodle createNoodle(String type) {19 Noodle noodle = null;20 if (type != null) {21 if ("yangchun".endsWith(type)) {22 noodle = new DBYangchunNoodle(nif);23 } else if ("dawan".equalsIgnoreCase(type)) {24 noodle = new DBDawanNoodle(nif);25 }26 }27 return noodle;28 }29 30 }
对于抽象工厂模式的总结:抽象工厂也是工厂模式的一种,本质上还是封装对象的创建。在本例子中我们可以看到,抽象工厂将食材的创建全部封装到抽象工厂中,不同的地区可以根据当地的特点来创建属于本地区的食材供应市场,而整个程序不需要因为地域之间不同而发生改变,每个区域只要创建一个食材供应市场,然后在自己店铺的系统中指定它既可。
工厂方法与抽象工厂之间的区别:
- 利用工厂方法创建对象,需要扩展一个类,并覆盖对应的工厂方法
- 提供一个封装对象创建的抽象类型,这个类型的子类或者是实现类定义了对象创建的方法,然后实例化这个工厂,并将其传到需要需要使用它的地方
- 工厂方法封装的是某一类对象的创建,每次只提供一个对象
- 抽象工厂封装的是一群相关的产品集合,可以同时提供多个对象
- 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象
- 抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中
如有错误,恳请读者指正!
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。