设计模式学习之Factory Method模式和Abstract Factory模式
终于到了工厂模式了,说起工厂模式,不得不把工厂方法模式和抽象工厂模式结合起来说,这两种模式都有工厂,乍听起来还真容易混淆,但它们却是不相同的两种模式,但又互相有联系。那么这两者之间各有什么用途,互相之间又有什么联系呢?一个一个来吧。
既然说起了工厂模式,那么首先有一点是需要搞清的,那就是,所有的工厂模式都是为了将对象的创建过程封装起来,要么 将创建过程隔离出来 ,要么 将创建过程抽象成接口。
那么,在说这两种模式之前,先说一下简单工厂,所谓的简单工厂,其实就是一种最简单的将创建过程隔离的设计方法。我们通常在创建一个对象时,都会用到如下语句:
Object o=new Object();
即new一个对象,但这种做法是最最基本最最原始的创建对象的方法,在面向对象的设计中,我们必须要遵循一个原则: 要依赖抽象,不要依赖具体类 。所以,这种做法因为太过具体,所以我们得想办法把它抽象出来,怎么抽象呢,用简单工厂可以这样实现:
1 public class Client 2 { 3 public void do() 4 { 5 Object o=SimpleFactory.createObject(); 6 } 7 } 8 public class SimpleFactory 9 { 10 public static Object createObject() 11 { 12 Object o=new Object(); 13 return o; 14 } 15 }
咋看起来变化不大,不就是吧new Object改为一个类的静态方法了吗(其实也可以用非静态方法,不过需要先实例化对象),但这样做却可以适应需求的改变,比如说,我现在想要根据不同的类型创建不同的对象,如果直接用new方法,则会在do方法里面写上很多歌new Object()的语句,而且还有很多的判断,每当新增加一种类型,就得改动Client类代码。而如果将创建对象的过程用简单工厂封装起来,则只需要改动简单工厂里面的代码:
1 //直接用new方法 2 public class Client 3 { 4 public void do(String type) 5 { 6 Object o; 7 switch(type) 8 { 9 case "type1":o=new Object1();break;//Object1、Object2都是Object的子类 10 case "type2":o=new Object2();break; 11 //... 12 } 13 } 14 } 15 16 //采用简单工厂封装创建过程 17 public class Client 18 { 19 public void do(String type) 20 { 21 Object o=SimpleFactory.createObject(type); 22 } 23 } 24 public class SimpleFactory 25 { 26 public static Object createObject(String type) 27 { 28 Object o; 29 switch(type) 30 { 31 case "type1":o=new Object1();break;//Object1、Object2都是Object的子类 32 case "type2":o=new Object2();break; 33 //... 34 } 35 return o; 36 } 37 }
但这样做还是会带来不便,因为还是要改动代码,增加新的判断分支,怎样才能更好的封装以增强可维护性和可扩展性呢,工厂方法模式和抽象工厂模式就可以大大增强简单工厂的作用。
那么首先说说工厂方法模式,先说基本概念吧
- 工厂方法模式:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。
- 适用性:
- 当一个类不知道它所必须创建的对象的类的时候。
- 当一个类希望由它的子类来指定它所创建的对象的时候。
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
工厂方法模式中,最重要的一点是“让子类决定实例化那一个类”,这一点怎么才能做到呢,而且这样做有什么好处呢?
还是举例子最好了,对于工厂模式,能举的最好的例子当然是与生产产品有关的了,现在,我们假定生产一种手机,那么我们知道,每种手机都需要很多零部件,然后进行组装,打磨,包装等等,对于手机最主要的零件cpu来说,就有不同类型的cpu,比如高通,intel,苹果,德州仪器,或者mtk等等,那么我们在生产手机时,就需要使用某种芯片,就相当于创建这些对象。但不同手机可以使用不同的芯片,如果采用简单工厂来生产这些芯片,就像下面一样:
1 public class Cellphone 2 { 3 Cpu cpu; 4 Memory memory; 5 Screen screen; 6 public void getCpu(); 7 public void makePhone(String phoneType) 8 { 9 switch(phoneType) 10 { 11 case "iphone4s":cpu=CpuFactory.createCpu("apple A5");break; 12 case "三星i9100":cpu=CpuFatory.createCpu("高通");break; 13 case "摩托罗拉me525":cpu=CpuFactory.createCpu("高通");break; 14 case "华为8500":cpu=CpuFactory.createCpu("德州仪器");break; 15 case "诺基亚":cpu=CpuFactory.createCpu("intel");break; 16 //... 17 } 18 } 19 public void package(); 20 } 21 22 public class CpuFactory 23 { 24 public static Cpu createCpu(String cpuType) 25 { 26 Cpu cpu; 27 switch(cpuType) 28 { 29 case "apple A5":cpu=new AppleCpu("A5");break; 30 case "apple A5X":cpu=new AppleCpu("A5X");break; 31 case "高通1代":cpu=new QualcommCpu("1");break; 32 case "高通2代":cpu=new QualcommCpu("2");break; 33 case "德州仪器":cpu=new TiCpu();break; 34 case "intel":cpu=new IntelCpu();break; 35 //... 36 } 37 } 38 }
那么,如果增加新的cpu,就要在CpuFactory里面再增加新的判断分支。而如果使用工厂方法模式,就可以这样:
1 public class Cellphone 2 { 3 protected String type; 4 protected Cpu cpu; 5 protected Memory memory; 6 protected Screen screen; 7 protected abstract Cpu getCpu(); 8 public Cellphone(String type) 9 { 10 this.type=type; 11 } 12 public void makePhone() 13 { 14 cpu=getCpu(); 15 //.. 16 } 17 public void package(); 18 } 19 20 public class Iphone extends Cellphone 21 { 22 public Cpu getCpu() 23 { 24 switch(type) 25 { 26 case "3gs":cpu=CpuFactory.createCpu("apple A3"); 27 case "4":cpu=CpuFactory.createCpu("apple A5"); 28 case "4s":cpu=CpuFactory.createCpu("apple A5X"); 29 case "5":cpu=CpuFactory.createCpu("apple A6"); 30 //... 31 } 32 } 33 } 34 public class Motorola extends Cellphone 35 { 36 public Cpu getCpu() 37 { 38 switch(type) 39 { 40 case "millstone":cpu=CpuFactory.createCpu("高通1代");break; 41 case "me525":cpu=CpuFactory.createCpu("高通2代");break; 42 case "millstone2":cpu=CpuFactory.createCpu("高通2代");break; 43 case "xt860":cpu=CpuFactory.createCpu("高通3代");break; 44 //... 45 } 46 } 47 } 48 //... 49 public class CpuFactory 50 { 51 public static Cpu createCpu(String cpuType) 52 { 53 Cpu cpu; 54 switch(cpuType) 55 { 56 case "apple A5":cpu=new AppleCpu("A5");break; 57 case "apple A5X":cpu=new AppleCpu("A5X");break; 58 case "高通1代":cpu=new QualcommCpu("1");break; 59 case "高通2代":cpu=new QualcommCpu("2");break; 60 case "德州仪器":cpu=new TiCpu();break; 61 case "intel":cpu=new IntelCpu();break; 62 //... 63 } 64 } 65 }
对于上例来说,我们将不同类型的手机分离了出来,让它们共同继承Cellphone基类,显得结构清晰,便于扩展,比如现在如果有一款三星的手机,就只需要继承新建一个Samsung类然后继承Cellphone类,然后重写getCpu方法即可实现三星手机的cpu采购过程。也就是说,getCpu作为一个抽象的创建cpu的方法,让子类去具体实现。
像这种结构,就体现了“具体的手机产品需要具体的cpu类型”的设计。也就是“定义一个用于创建对象的接口(getCpu),让子类决定实例化哪一个类”,在Iphone类和Motorola类中分别实现了getCpu方法,使用简单工厂产生了各种的cpu。在这里,并不是采用工厂方法模式取代简单工厂,而是将简单工厂也应用到了工厂方法模式当中,因为这两者是不同的设计思想,也即 工厂方法模式是将创建过程抽象成接口 ,而 简单工厂是将创建过程隔离出来 。而抽象工厂模式则是这两种思想的进一步结合和升华。
- 抽象工厂模式:
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 - 适用性:
- 一个系统要独立于它的产品的创建、组合和表示时。
- 一个系统要由多个产品系列中的一个来配置时。
- 当你要强调一系列相关的产品对象的设计以便进行联合使用时。
- 当你提供一个产品类库,而只想显示它们的接口而不是实现时。
前面的例子虽然将不同的手机种类从判断分支中解脱了出来,但对于cpu的制作仍然显得比较乱,也就是说CpuFactory承担了所有的cpu制作任务(搞垄断啊:>),而cpu的型号五花八门,同一种型号的cpu也有很多的版本,如果放到一个工厂生产,实在不是一个聪明的做法,所以,我们自然考虑将不同的cpu从一个简单工厂解脱出来,分别由不同的工厂来生产(这样才有竞争嘛:>),因此,我们将简单工厂改造成抽象工厂,怎么改造?看下面:
1 //抽象工厂类 2 public class CpuFactory 3 { 4 Cpu cpu; 5 public abstract Cpu createCpu(String type); 6 } 7 //苹果cpu工厂类 8 public class AppleCpuFactory extends CpuFactory 9 { 10 public Cpu createCpu(String type) 11 { 12 switch(type) 13 { 14 case "A3":this.cpu=new AppleCpu("A3");break; 15 case "A5":this.cpu=new AppleCpu("A5");break; 16 case "A5X":this.cpu=new AppleCpu("A5X");break; 17 case "A6":this.cpu=new AppleCpu("A6");break; 18 //... 19 } 20 } 21 } 22 //高通cpu工厂类 23 public class QualcommCpuFactory extends CpuFactory 24 { 25 public Cpu createCpu(String type) 26 { 27 switch(type) 28 { 29 case "1代":this.cpu=new QualcommCpu("1");break; 30 case "2代":this.cpu=new QualcommCpu("2");break; 31 case "3代":this.cpu=new QualcommCpu("3");break; 32 //... 33 } 34 } 35 } 36 //德州仪器工厂类 37 public class TiCpuFactory extends CpuFactory 38 { 39 public Cpu createCpu(String type) 40 { 41 switch(type) 42 { 43 case "1代":this.cpu=new TiCpu("1");break; 44 case "2代":this.cpu=new TiCpu("2");break; 45 case "3代":this.cpu=new TiCpu("3");break; 46 //... 47 } 48 } 49 } 50 //cpu产品抽象类 51 public class Cpu 52 { 53 protected float frequency; 54 protected String type; 55 public Cpu(String type) 56 { 57 this.type=type; 58 } 59 } 60 //苹果cpu产品类 61 public class AppleCpu extends Cpu 62 { 63 } 64 //高通cpu产品类 65 public class QualcommCpu extends Cpu 66 { 67 } 68 //德州仪器cpu产品类 69 public class TiCpu extends Cpu 70 { 71 }
使用这种模式,就将各种具体的工厂分出了清晰的结构,也就是将工厂也抽象成接口了,这就是为什么叫“抽象工厂”的原因。
既然我们升级简单工厂为抽象工厂,那么创造产品自然就要用新的接口方法了:
1 public class Cellphone 2 { 3 protected String type; 4 protected Cpu cpu; 5 protected Memory memory; 6 protected Screen screen; 7 protected CpuFactory cpuFactory; 8 protected abstract Cpu getCpu(); 9 public Cellphone(String type) 10 { 11 this.type=type; 12 } 13 public void makePhone() 14 { 15 cpu=getCpu(); 16 //.. 17 } 18 public void package(){}; 19 } 20 public class Iphone extends Cellphone 21 { 22 public Cpu getCpu() 23 { 24 this.cpuFactory=new AppleCpuFactory();//由于创建产品的方法不再是静态方法,所以需要创建实例 25 switch(type) 26 { 27 case "3gs":cpu=this.cpuFactory.createCpu("A3"); 28 case "4":cpu=this.cpuFactory.createCpu("A5"); 29 case "4s":cpu=this.cpuFactory.createCpu("A5X"); 30 case "5":cpu=this.cpuFactory.createCpu("A6"); 31 //... 32 } 33 } 34 } 35 public class Motorola extends Cellphone 36 { 37 public Cpu getCpu() 38 { 39 this.cpuFactory=new QualcommCpuFactory(); 40 switch(type) 41 { 42 case "millstone":cpu=this.cpuFactory.createCpu("1");break; 43 case "me525":cpu=this.cpuFactory.createCpu("2");break; 44 case "millstone2":cpu=this.cpuFactory.createCpu("2");break; 45 case "xt860":cpu=this.cpuFactory.createCpu("3");break; 46 //... 47 } 48 } 49 }
这样一来,整个结构就清晰多了,用一句话概括就是:由具体的手机使用具体的工厂生产具体的cpu,但手机、工厂和cpu都通过接口进行交互,较好的封装了各自的实现,从而达到了较好的可扩展性,大大降低了各自的耦合性。现在,如果要添加新的手机、新的cpu,就可以建立新类型的工厂来实现对新的cpu的创建过程。
转载于:https://www.cnblogs.com/everdom/archive/2012/07/27/2611483.html
设计模式学习之Factory Method模式和Abstract Factory模式相关推荐
- 设计模式学习总结1 - 创建型1 - Abstract Factory抽象工厂模式
AbstractFactory抽象工厂模式(创建型) 作用: 这种模式支持创建不同的对象,这些对象功能接近且一般都是在一起创建的.抽象工厂被具体化成不同的工厂来创建类似产品的不同产品.这种模式将类于使 ...
- 设计模式:工厂方法模式(Factory Method)和抽象工厂模式(Abstact Factory)
欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...
- 设计模式(6)——抽象工厂模式(Abstract Factory Pattern,创建型)
1.概述 使用设计模式可以提高代码的可复用性.可扩充性和可维护性.抽象工厂模式(Abstract Factory Pattern)属于创建型模式,为创建一组相关或者相互依赖的对象(产品族)提供一个抽象 ...
- 设计模式的征途—4.抽象工厂(Abstract Factory)模式
上一篇的工厂方法模式引入了工厂等级结构,解决了在原来简单工厂模式中工厂类职责太重的原则,但是由于工厂方法模式的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,从而增加系统开销.那么,我们应该 ...
- 设计模式之笔记--抽象工厂模式(Abstract Factory)
抽象工厂模式(Abstract Factory) 定义 抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 类图 描述 多个抽象产品 ...
- 设计模式(3):抽象工厂模式(Abstract Factory Pattern)
1.继续工厂方法模式 在工厂方法模式中,介绍了一个工厂类创建一中产品,所有的工厂类都是基于接口实现的,所有的产品也是基于接口实现的.这样当增加新的产品的时候只需要实现新的工厂类和新的产品类即可,满足了 ...
- Java经典设计模式-创建型模式-抽象工厂模式(Abstract Factory)
2019独角兽企业重金招聘Python工程师标准>>> 抽象工厂模式(Abstract Factory) 工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序, ...
- 3.2.3 抽象工厂模式(Abstract Factory) -《SSM深入解析与项目实战》
文章目录 3.2.3 抽象工厂模式(Abstract Factory) 概述 抽象产品接口 具体产品实现 抽象工厂 抽象工厂的实现 抽象工厂模式测试 演示结果 总结 3.2.3 抽象工厂模式(Abst ...
- 设计模式学习每天一个——Factory模式 和 Abstract Factory模式
工厂模式与抽象工厂模式的区别 转载于:https://www.cnblogs.com/windy86/p/4022551.html
最新文章
- python使用imbalanced-learn的AllKNN方法进行下采样处理数据不平衡问题
- MySQL笔记4:desc命令的两个用法
- VC++文件编程操作实例
- Apache ZooKeeper - Leader Election使用场景
- 1.9 多态性:什么是多态?
- 打印斐波那契数列前10位数字
- CSS 普通流 和 行格式化上下文 IFC
- Rider找不到指定的 SDK Microsoft.NET.Sdk
- isupper_Python字符串isupper()
- python爬虫︱百度百科的requests请求、百度URL格式、网页保存、爬虫模块
- Atitit usrQBF2312 命名空间pkg 以及 api命名 spec规范
- 怎么用PDF转换器将PDF文件转成txt
- U盘 量产记录(俩盘符合并为一个盘符)
- 阿里云80端口无法访问
- Unity摄像机平滑处理跟随
- 凉宫春日的忧郁[数学题]
- 怎么查看笔记本内存条型号_新买的笔记本如何查看笔记本内存条型号有哪些方法...
- 天作之合:水果与朗姆酒
- 一键将kafka,zookeeper安装为windows服务
- 用于CTF(MISC)的kali虚拟机更改过程记录
热门文章
- 【微信小程序】跳转到另一个微信小程序
- spring cloud Alibaba Sentinel中文文档
- 怎么用cmd关闭系统弹窗_SD卡受损怎么修复?教你一招三步搞定
- springboot 注解动态赋值_java springboot动态给注解属性参数赋值
- 系统相机裁剪比例_真皮、皮革自动裁剪机,拒绝材料浪费,一年可以节省十几万!...
- unity3d 绘制小地图_老师!我想用Tilemap做元气骑士款地图!
- python 模糊匹配文件名 glob_Python: glob匹配文件
- decode函数吗 jsp_JSP中js传递和解析URL参数以及中文转码和解码问题
- mysql 实时备份_MySQL实现实时备份[转]
- 纯文本邮件转为html,将纯文本电子邮件转换为HTML邮件