面向对象设计模式纵横谈:Abstract Factory 抽象工厂模式(笔记记录)
今天是设计模式的第二讲,抽象工厂的设计模式,我们还是延续老办法,一步一步的、演变的来讲,先来看看一个对象创建的问题。
1、如何创建一个对象
常规的对象创建方法:
![]()
这样的创建对象没有任何问题,也可以很好的使用。但是如果有需求的变化,比如,如果我们换了一种道路呢,这时候就出现了问题。
new的问题:
-实现依赖,不能应对“具体实例化类型”的变化,Road是具体类型,所有使用到Road的地方都需要变化。如果经常变化,怎么解决具体类型的变化呢?
解决思路:
-封装变化点——哪里变化,封装哪里
-潜台词:如果没有变化,当然不需要额外的封装!
2、简单工厂模式的由来
先说明一点,“简单工厂模式”没有写在Gof的23种设计模式里面,它是“工厂模式”的引子。
变化点在“对象创建”,因此就封装“对象创建”
面向接口编程——依赖接口(此接口不是语言层面的Interface,此接口可以是:Interface&抽象类),而非依赖实现
最简单的解决方法:
![]()
这样做,可以隔离客户程序和具体Road类型的变化,客户程序依赖比较稳定的RoadFactory类型,这样一来,客户端的使用的接口就比较稳定了。
3、创建一系列相互依赖的对象
一个对象的问题解决了,那多个对象的创建问题怎么解决呢?
假设一个游戏开发场景:
我们需要构造“道路”、“房屋”、“地道”、“丛林”……等等对象
![]()
![]()
很不错,解决了一批对象的创建问题,这样可以保持客户程序使用接口的稳定性。
4、多批对象的创建
简单工厂的问题:
-不能应对“不同系列对象”的变化。比如有不同风格的游戏场景——对应不同风格的道路、房屋、地道……客户程序相对稳定,但是静态的简单工厂却可能成为变化点。
如何解决:
-使用面向对象的技术来“封装”变化点,我们就可以使用“抽象工厂”设计模式
动机(Motivation)
在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。
如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?
意图(Intent)
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。
结构(Structure)
![]()
ProductA1和ProductB1是一个系列,ProductA2和ProductB2是另一个系列。ConcreteFactory1是创建系列1的工厂方法,ConcreteFactory2是创建系列2的工厂方法。客户程序Client只依赖了AbstractFactory和AbstractProductA、AbstractProductB,也就是客户程序不依赖于具体实现,而是只依赖与抽象类。
如果现在需要创建一个系列3运用到客户程序,我们只需要再写一个系列3的工厂,继承自AbstractFactory,这个工厂提供了2个实现:
CreateProductA();
CreateProductB();
它们分别返回ProductA3(继承自AbstractProductA)、ProductB3(继承自AbstractProductB)。
也就是说,如果新增了系列3,Client程序可以完全不用改动,可能只需要该一些配置文件,增加一些新dll就可以应对变化。
游戏框架中的AbstractFactory应用
![]()
![]()
这个例子里,Road就是AbstractProductA1,Building就是AbstractProductB1,FacilitiesFactory就是AbstractFactory。
客户程序
![]()
可以看出,客户程序依赖的全部是抽象类,在客户程序代码中没有出现过任何具体的实现类。因为在系列需要变化的时候,是不需要改变抽象类的,只是增加一个抽象类的实现而已,又由于客户程序只依赖于抽象,所以系列变化的时候客户程序完全无需变化。
一个现代风格系列的实现
![]()
具体现代风格系列工厂实现
![]()
应用到具体程序(现代风格)
![]()
应用到具体程序(经典风格)
![]()
可以看出,风格由Modern改变为Classic的时候,我们封装好的GameManager客户程序没有改变,这就是我们想要的结果。GameManager的逻辑非常复杂,现在它的稳定,能够大大方便我们的工作。
AbstractFactory模式的几个要点
1.如果没有应对“多系列对象创建”的需求变化,则没有必要使用AbstractFactory模式,这时候使用简单的静态工厂完全可以。
2."系列对象"指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中“道路”与“房屋”的依赖,“道路”与“地道”的依赖。
3.AbstractFactory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。
4.AbstractFactory模式经常喝FactoryMethod模式共同组合来应对“对象创建”的需求变化。
例如,如果是风格不经常变化,而是其他内容变化(例如今天要添加道路的类、明天要添加沙漠的类),这样用这种抽象工厂模式反而会把系统搞的很糟糕,因为抽象工厂类中的子类变化了,所有实现抽象工厂的类都需要去变化,重新实现,重新编译和部署。
也就是说关键要看变化的方向和轴线在哪里。如果变化的轴线在多风格,那抽象工厂模式就很适用;如果变化的轴线在抽象工厂里面的对象,就最好不要使用这种模式。
.NET框架中的AbstractFactory应用
在ASP.Net编译的时候,首先把aspx页面文件先编译成一个类,然后再把CodeBehind又编译成一个类,CodeBehind的类继承自Page类,而aspx页面的类又继承自CodeBehind类。在aspx页面中处理的WebControl和HtmlControl实际上用到了AbstractFactory的运用,但是这个运用更多是体现在业务层次。
Builder模式和AbstractFactory模式的区别
Builder模式更强调的是对象组成部分的构建的过程,而且这个构建的过程很稳定,但是各个组成部分在变化,最后组合成一个整体的对象。
AbstractFactory模式构建的是一系列相互依赖、相互关联的对象集合。
面向对象设计模式纵横谈:Abstract Factory 抽象工厂模式(笔记记录)的更多相关文章
- Java设计模式:Abstract Factory(抽象工厂)模式
概念定义 抽象工厂(Abstract Factory)模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 抽象工厂模式中,系统的产品有多于一个的产品族(一个产品族里定义多个产品) ...
- 设计模式(一): abstract factory抽象工厂模式 -- 创建型模式
1.定义 为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类. 2.适用场景 1.一个系统要独立于它的产品创建.组合和表示. 2.一个系统要由多个产品系列中的一个来配置. 3.当你要 ...
- 一天一个设计模式——Abstract Factory抽象工厂模式
一.模式说明 前面学习了工厂方法(Factory Method)模式.在工厂方法模式中,在工厂方法模式中,父类决定如何生成实例,但并不决定所要生成的具体类,具体的处理交由子类来处理.这里学习的抽象工厂 ...
- c++ 设计模式9 (Abstract Factory 抽象工厂模式)
5.2 抽象工厂模式 动机:在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作:同时,由于需求的变化,往往存在更多系列对象的创建工作. 代码示例: 实现利用数据库的业务逻辑,支持多数据库(Sq ...
- Abstract Factory抽象工厂模式
抽象工厂模式是是用一个超级工厂去创建其他工厂,简单点说就是工厂的父类,属于创建型模式. 目标:提供一个创建一组对象的方法,而无需指定它们具体的类(同工厂方法). 使用场景:系统的产品有多于一个的产品族 ...
- Abstract Factory 抽象工厂模式
提供一个创建一些列相关或相互依赖对象的接口,而无需指定它们具体的类. 抽象工厂顾名思义就是对工厂的抽象,它提供了一组创建抽象产品对象的操作接口,我们实际使用的是抽象工厂的派生类,派生类中提供了操作的具 ...
- 面向对象设计模式纵横谈:Factory Method 工厂方法模式(笔记记录)
从耦合关系谈起 耦合关系直接决定着软件面对变化时的行为 -模块与模块之间的紧耦合使得软件面对变化时,相关模块都要随之更改 -模块与模块之间的松耦合使得软件面对变化时,一些模块更容易被替换或者更改,但其 ...
- C#面向对象设计模式纵横谈——5.Factory Method 工厂方法模式(创建型模式)
动机 (Motivation) 在软件系统中,经常面临着“某个对象”的创建工作; 由于需求的变化,这个对象经常面临着剧烈的变化,但是它却拥有比较稳定的接口. 如何应对这种变化?如何提供一种“封装机制” ...
- 2.设计模式-Abstract Factory 抽象工厂模式
大神勿喷,不对的地方请指出来,学笔记而已. 解决的问题:应对多系列对象构建的变化或多系列(例如:崎岖的山路和平坦的马路属于一个系列) 不断的变化的创建. 使用场景:对象不变(比如有3个对象 " ...
随机推荐
- equals变量在前面或者在后面有什么区别吗?这是一个坑点
我就不废话那么多,直接上代码: package sf.com.mainTest; public class Test { public static void main(String[] args) ...
- AndroidStudio — Error:Failed to resolve: junit:junit:4.12错误解决
原博客:http://blog.csdn.net/u013443865/article/details/50243193 最近使用AndroidStudio出现以下问题: 解决:打开app下的buil ...
- 跨域问题,前端主动向后台发送cookie
跨域是什么? 从一个域名的网页访问另一个域名的资源,就会出现跨域.只要协议.端口.域名有一个不同就会出现跨域 例如: 1.协议不同 http://www.baidu.com:80 和 https:/ ...
- oracle常用的快捷键
最近在开发过程中,遇到一些麻烦,就是开发效率问题,有时候其他同事使用PLSQL 编程效率明显高于自己,观察了好久,才发现他使用PLSQL 已经很长时间了而且,他自己也在其中添加了好多快捷方式, 1.登 ...
- Hadoop1 Centos伪分布式部署
前言: 毕业两年了,之前的工作一直没有接触过大数据的东西,对hadoop等比较陌生,所以最近开始学习了.对于我这样第一次学的人,过程还是充满了很多疑惑和不解的,不过我采取的策略是还是先让环 ...
- MemCache超详细解读
MemCache是什么 MemCache是一个自由.源码开放.高性能.分布式的分布式内存对象缓存系统,用于动态Web应用以减轻数据库的负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高 ...
- [翻译]AKKA笔记 -ACTOR SUPERVISION - 8
失败更像是分布式系统的一个特性.因此Akka用一个容忍失败的模型,在你的业务逻辑与失败处理逻辑(supervision逻辑)中间你能有一个清晰的边界.只需要一点点工作,这很赞.这就是我们要讨论的主题. ...
- AngularJs之四
一,数据循环:特别要注意作用域 使用ng-repeat指令. <div ng-app="myApp" ng-controller="myCtrl"> ...
- SQL Server 游标运用:鼠标轨迹字符串分割
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 游标模板(Cursor Template) 鼠标轨迹字符串分割SQL脚本实现(SQL Code ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(42)-工作流设计-表建立
系列目录 工作流在实际应用中还是比较广泛,网络中存在很多工作流的图形化插件,可以做到拉拽的工作流设计,非常简便,再配合第三方编辑器,可以直接生成表单,我没有刻意的浏览很多工作流的实际设计,我认为工作流 ...