GOF《Design Patterns》第三章
*GOF巨作《Design Patterns》毫无疑问是设计模式的圣经,然而“从风格上讲,该书与其说是为学习者而写作的教程范本,还不如说是给学术界人士看的学术报告,严谨有余,生动不足。”〔孟岩〕本系列将《Design Patterns》中文版(结合英文版)中重要句子按句解析,作为自学笔记也给新接触设计模式的朋友一点借鉴。文中原文以粗体标出。我自己不明白的地方以〔TODO:〕标出,希望高手多多指点。
创建型模式抽象了实例化过程。两个问题:
-
何谓实例化过程?
-
什么叫做抽象?
所谓实例化过程,说白了就是创建对象的过程。在面向对象语言中,一般是指通过构造器(constructor)创建对象的过程。在Java和C#中通常用new这个关键字来创建对象,当然还有通过反射的方法,后者用的较少。一个对象实例化结束后并不一定就可以使用了,对于复杂的对象有时候还需要做一些装配,有时候也叫做初始化。后面我们说到实例化没有特殊说明,就是指的用new这个关键创建对象。[e.g instance = new SomeConcreteClass();]
这个过程如何抽象呢?所谓抽象就是掩盖具体的东西,这里面那个东西是具体的概念呢?显然是构造器,也就是SomeConcreteClass这个类。这是一个具体类,当我们的代码里面出现具体类的时候,我们就依赖了具体实现,这违背了DIP原则。抽象就是客户端只了解自己需要某个实例,但是不了解改实例的创建过程,或者说不了解其构造函数的签名(包括构造器的名字即类名和构造参数)。
它们帮助一个系统独立于如何创建、组合和表示它的那些对象。原文是:They help make a system independent of how it’s objects created, composed and represented.这句话说明创建型模式的作用是使得系统独立于系统中对象的创建,组合和表示。从这一点上看,上一句说抽象了实例化过程中的实例化过程是包含装配过程(组合)的。创建型模式帮助系统独立于其对象的创建和组合是容易理解的。比如Factory Method通过一个返回接口的方法来返回对象实例,客户端并不了解对象的创建过程;Builder模式隔离了对象的各个部分的创建和其组合过程。那么独立于表示如何理解呢?“表示”在这里可以理解为对同一个接口的不同实现。
[e.g. (感谢Lenny Primark)
List<Number> numbers = numbersFactory.createNumbers(5, 10); // create five numbers with values of 10
工厂方法返回的实例可能是如下的任何一个“表示”:
-
it can give you LinkedList<Number> or ArrayList<Number>
-
it can give you List<IntegerNumber> or List<DoubleNumber>
-
or any other combination.
创建型模式返回给你的是借口,而实现和实际数据的表示细节则被隐藏了。]
一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象。
随着系统演化得越来越依赖与对象复合而不是类继承,创建型模式变得更为重要。首先给我们指明了演化的方向,越来越依赖于对象复合而不是继承,然后在这个前提下,应用创建型模式,我想这是鼓励对象创建型模式。
当这种情况发生时,重心从对一组固定行为的硬编码(hard-coding)转移为定义一个较小的基本行为集,这些行为可以被组合成任意数目的更复杂的行为。类继承实际上是“静态的”固定的行为,是在编译期确定了的行为,而对象复合追求的是通过较小的基本行为集组合成复杂的行为,通常是支持运行时改变的组合方式的。
这样创建有特定行为的对象要求的不仅仅是实例化一个类。即,还有可能要负责装配过程。
在这些模式中有两个不断出现的主旋律。第一,它们都将关于该系统使用哪些具体的类的信息封装起来。第二,它们隐藏了这些类的实例是如何被创建和放在一起的。第一个里面封装也就是说,客户代码不了解自己使用的具体类是什么。第二个就很明白了,但是与第一段中相比,没有提到“represented”(表示)这个意思。
整个系统关于这些对象所知道的是有抽象类所定义的接口。这里整个系统实际上说的是客户代码,整个系统如果包含具体类在内当然要了解具体类了。
因此创建型模式在什么被创建,谁创建它,它是怎样被创建的,已经何时创建这些方面给予你很大的灵活性。什么被创建:通过产品接口隐藏具体类。谁创建它:通过工厂接口隐藏具体工厂。它是怎样被创建:Builder抽象方法隐藏创建过程。何时创建:单件模式隐藏创建时机。〔TODO:这里还要加上其他几个模式分别封装什么。〕
它们允许你用结构和功能差别很大的“产品”对象配置一个系统。配置可以是静态的(即在编译时指定),也可以是动态的(在运行时)。结构和功能差别很大的“产品”应该实现相同的接口。
有时创建型模式是相互竞争的。例如,在有些情况下Prototype或Abstract Factory用起来都很好。而在另外一些情况下它们是互补的:Builder可以用其他模式去实现某个构件的创建。Prototype可以在它的实现中使用Singleton。
接下来作者举了一个例子,这里不重述了。但是还是有几点需要注意。
作者把Enter这个方法放入MapSite中,而不是某个叫做Player的类中。这里面包含了很多的智慧和经验。当然我不排除Player类中应该包含一个类似与Move之类的方法,但是这个方法应该调用Mapsite的Enter方法。试想,对于Move这个动作和其响应如果全部放在Player这个类中完成将是如下的效果:
[
public void Move(Direction d)
{
if(currentRoom.GetSide(d) is Room){}
else if (currentRoom.GetSide(d) is Wall){}
else if (currentRoom.GetSide(d) is Door)
{
if (door.isOpen){}
else{}
}
}
] 毫无疑问这种方式的可读性,扩展性都很差。Enter为更复杂的游戏操作提供了一个简单基础。在一个真正的游戏中,Enter可以将游戏者对象作为一个参数。
作者在给出CreateMaze方法之后的评价,考虑到这个函数所做的仅是创建一个有两个房间的迷宫,它是相当复杂的。这个复杂性是因为客户端负责了太多的职能。Room的构造器可以提前用墙壁来初始化房间的每一面。这样会使得客户端代码稍微简单一些。这个成员函数真正的问题不在于它的大小而在于它不灵活。
创建型模式显示如何使得这个设计更灵活,但未必会更小。所以使用模式的时候,要抛弃这个观点,认为好的设计是小的设计,而是灵活的可扩展的设计。
当前的设计不易扩展,其最大的障碍是对被实例化的类进行硬编码。在本章导论部分的最后,作者给出了创建型模式的解决方案。
-
Factory Method:CreateMaze调用虚函数而不是通过new来创建Room,Wall和Door。Factory Method实际上简单的令你惊讶!任何时候,当你存在一个虚拟的(抽象的)函数其返回值是一个接口(抽象类),你就在使用Factory Method了。(插一句,理解一个模式的简单性有时候比理解其复杂性更重要,很多人对Factory Method模式敬而远之,就是没有理解其简单性。)建议您参考一下我的另一篇文章:《没有Factory这个模式》。
-
Abstract Factory:CreateMaze不是调用自己的虚函数,而是从外界传入一个对象(抽象工厂)给它。CreateMaze方法调用这个对象的方法(也是虚方法)来创建Room,Wall和Door。
-
Builder:(TODO:等我看完了再补充:)
-
Prototype:(TODO:等我看完了再补充:)
-
Singleton:保证每个游戏中仅有一个迷宫,而且所有的对象都可以迅速访问它――二不需要求助于全局变量或函数。Singleton也使得迷宫易于扩展或者替换,且不需要变动已有代码。Singleton如此受到
争议,我就不多说了。作者在最后加一句“易于扩展或者替换”,还强调“不需要变动已有代码”确实让人不解。(TODO:哪位高手出来解释一下?)
分享到:
相关推荐
在线阅读地址:设计原则创建型模式作用:将创建与使用代码解耦结构型模式作用:将不同的功能代码解耦桥接模式装饰器模式适配器模式外观模式组合模式享元模式行为型模式(更新中...)作用:将不同的行为代码解耦观察...
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:...
3.6 创建型模式的讨论 89 第4章 结构型模式 91 4.1 Adapter(适配器)—类对象结构型 模式 92 4.2 Bridge(桥接)—对象结构型 模式 100 4.3 Composite(组成)—对象结构型 模式 107 4.4 Decorator(装饰)—对象...
创建型模式设计到将对象实例化,这类模式都提供了一个方法,将客户从所需要的实例化对象中解耦。 原型模式 Prototype 结构型设计模式 结构型模式可以让你把类或者对象组合到更大的结构中。 桥接模式 Bridge 外观模式...
第二部分 创建型模式 第8章 简单工厂模式 第9章 工厂方法模式 第10章 抽象工厂模式 第11章 单件模式 第12章 生成器模式 第13章 原型模式 第三部分 结构型模式 第14章 适配器模式 第15章 桥接模式 第16章 组合模式 第...
23种设计模式(Design Pattern)的C++实现范例,包括下面列出的各种模式,代码包含较详细注释。另外附上“设计模式迷你手册.chm”供参考。 注:项目在 VS2008 下使用。 创建型: 抽象工厂模式(Abstract Factory) 生成...
23种设计模式的讲解:设计模式分为创建型模式、结构型模式、行为型模式 创建型模式 简单工厂模式 详细的讲解文件在 工厂方法模式 详细的讲解文件在 抽象工厂模式 详细的讲解文件在 建造者模式 详细的讲解文件在 单例...
然后分别讲述了创建型模式、结构型模式和行为型模式。每一类设计模式又包括若干种具体模式,共有23种。在介绍每种模式时,给出了一个或多个应用该模式的示例,以便于理解,且这些示例都是能完全运行的程序,包含在随...
《设计模式》一书共归纳了23种设计模式,这些设计模式被分为三大类:创建型模式,结构型模式,行为型模式 本文为《 JavaScripti计模式与开发实践》一书的学习与思考。 基础知识 设计模式 创建型模式:封装创建对象...
这些模式可以分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、 行为型模式(Behavioral Patterns) 创建型模式 工厂模式(Factory Pattern) 抽象工厂模式(Abstruct Factory ...
创建型模式---这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。 工厂模式(Factory Pattern) ...
Creational(创建型模式) Structural Patterns(结构型模式) Bridge Composite Behavioral Patterns(行为型模式) Command Interpreter Mediator Memento Observer State Strategy Template Method Visitor 项目...
设计模式一组示例 Java 设计模式创建型设计模式单身人士建造者因子法抽象方法结构设计模式正面适配器装饰器桥合成的代理人蝇量级行为设计模式命令战略游客观察员纪念调解员责任链状态模板额外的控制反转数据传输对象
百度地图毕业设计源码 设计模式(Design Patterns)[原文地址:] ——可复用面向对象软件的基础 ...创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器
java7 源码 design-patterns 这个项目是 java 23 种设计模式的 demo 实现; 我使用的 ...中我会尝试使用函数式编程以及 ...之后的新特性,所以如果运行时出现异常请先检查自己 ...创建型 | 结构型 行为型
3.6 创建型模式的讨论 89 第4章 结构型模式 91 4.1 adapter(适配器)—类对象结构型 模式 92 4.2 bridge(桥接)—对象结构型 模式 100 4.3 composite(组成)—对象结构型 模式 107 4.4 decorator(装饰)...
Oh, my design patterns记录了我学习设计模式时写的文章以及代码。若有纰漏,欢迎指正与交流。:grinning_face:点击查看电子书,体验更好 :backhand_index_pointing_right: 创建型 (Creational)Java Kotlin结构型...
创建型模式 抽象工厂模式 工厂方法模式(工厂方法模式) 构造器模式(builder pattern) 原型模式 单例模式(单例模式) 结构型模式 适配器模式 改进模式(bridge pattern) 组合模式 装饰器模式 门面模式 享元模式...
创建型模式 1.1 工厂方法(FactoryMethod) 1.2 抽象工厂(AbstractFactory) 1.3 建造者模式(Builder) 1.4 单态模式(Singleton) 1.5 原型模式(Prototype) #####2 结构型模式 2.1 适配器模式(Adapter) 2.2 ...
3.6 创建型模式的讨论 89 第4章 结构型模式 91 4.1 Adapter(适配器)—类对象结构型 模式 92 4.2 Bridge(桥接)—对象结构型 模式 100 4.3 Composite(组成)—对象结构型 模式 107 4.4 Decorator(装饰)—对象...