《Head First design patterns》读书笔记
本文遵循“署名-非商业用途-保持一致”创作公用协议
终于肯完了《Head First design patterns》,顺便把用Google笔记本所做的笔记贴出来记录下~~
OO基础
抽象, 封装,多型,继承
OO原则
1,封装变化
2,多用组合,少用继承
3,针对接口编程,不针对实现编程
4,为交互对象之间的松耦合设计而努力
5,为扩展开放,对修改关闭
6,依赖倒置原则(Dependency Inversion Principle)
7,最少知识原则(Least Knowledge),只和你的密友谈话。
8,好莱坞原则:别调用我们,我们会调用你。
9,单一责任原则:一个类应该只有以一个引起变化的原因。
1,封装变化--策略模式(封装不同的算法--鸭子示例)2,多用组合,少用继承--策略模式(组合算法--鸭子示例)3,针对接口编程,不针对实现编程4,为交互对象之间的松耦合设计而努力--观察者模式(出版者/订阅者--天气预报与布告板示例)5,对扩展开放,对修改关闭--装饰者模式(咖啡与调料示例,java的IO库示例)6,要依赖抽象,不要依赖具体类。--工厂方法模式(pizza店与pizza示例)--抽象工厂模式(pizza与原料示例)7,最少知识原则--外观模式(家庭影院示例)8,好莱坞原则:别调用我们,我们会调用你在好莱坞原则下,我们允许底层组件将自己挂钩到系统上,但是高层组件会决定什么时候和怎样使用这些低层组件。换句话说,高层组件对待低层组件的方式是“别调用我们,我们会调用你”--模板方法模式(泡咖啡和泡茶示例)9,单一责任原则-迭代器模式(不同的菜单实现与女招待:ArrayList与数组)
设计模式
第一章 Strategy-策略模式
策略模式:定义算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
第二章 Observer-观察者模式
观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。
第三章 装饰者模式
装饰者模式定义:动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
示例:starbuzz 星巴克咖啡调料价格
设计原则:类应该对扩展开放,对修改关闭。
解释:
1,装饰者和被装饰者对象有相同的超类型;
2,既然装饰者和被装饰者对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象替代它。
3,装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,已达到特定的目的。
4,对象可以在任何时候被装饰,所以可以在运行时动态地,不限量地用你喜欢的装饰者来装饰对象。
要点:
--组合和委托可用于在运动时动态地加上新的行为;
--除了继承,装饰者模式也可以让我们扩展行为;
--装饰者模式意味着一群装饰者类,这些类用来包装具体组件;
--装饰者类反映出被装饰的组件类型(事实上,他们具有相同的类型,都经过接口或继承实现)
--你可以用无数个装饰者包装一个组件;
--装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型;
--装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。
第四章 Factory Method-工厂方法模式 与Abstact Factory Method -抽象工厂模式
工厂方法模式定义了一个创建对象的接口,但有子类决定要实例化的类似哪一个。工厂方法让类把实例化推迟到子类。
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
要点:
-所有的工厂都是用来封装对象的创建。
-简单工厂,虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户程序从具体类解耦。
-工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象。
-抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中。
-所有工厂模式都通过减少应用程序与具体类之间的依赖性促进松耦合。
-工厂方法允许类将实例化延迟到子类进行。
抽象工厂创建相关的对象家族,而不需要依赖他们的具体类。
-依赖倒置原则,指导我们避免依赖具体类型,而要 尽量依赖抽象。
-工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体类编程。
第五章 Singleton- 单件模式
单件模式-确保一个类只有一个实例,并提供一个全局访问点。
第六章 命令模式
命令模式将请求封装成对象,这可以让你使用不同的请求,队列,或者日志请求来参数化其他对象。命令模式也可以支持撤销操作。
示例:遥控器
第七章 Adapter-适配器模式和Facade-外观模式
适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
有两种分类:类适配器和对象适配器。
适配器模式示例:火鸡变鸭子,JDK的迭代器
外观模式示例:家庭影院
第八章 模板方法模式
模板方法模式在一个方法(称为模板方法)中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
钩子(hook)是一种被声明在抽象类中的方法,但只有空的或者默认的实现。钩子的存在可以让子类有能力对算法的不同点进行挂钩,要不要挂钩,由子类自行决定。
示例:泡咖啡和泡茶
要点:
-模板方法定义了算法的步骤,把这些步骤的实现延迟到子类。
-模板方法模式为我们提供了一种代码复用的重要技巧。
-模板方法的抽象类可以定义具体方法,抽象方法和钩子。
-抽象方法由子类实现。
-钩子是一种方法,它在抽象类中不做事,或者只做默认的事情,子类可以选择要不要去覆盖它。
-好莱坞原则告诉我们,将决策权放在高层模块中, 以便决定如何以及何时调用低层模块。
-策略模式和模板方法模式都封装算法,一个用组合,另一个用继承。
-工厂方法是模板方法的一个特殊版本。
第九章 迭代器(Iterator)与组合模式(Composite)--管理良好的集合
迭代器模式提供一个方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
组合模式允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
示例:菜单及其子菜单(树形结构)
组合模式让我们能用树形方式创建对象的结构,树里面包含了组合以及个别的对象。使用组合结构,我们能把相同的操作应用在组合和个别对象上。换句话说,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别。
何时使用组合模式:当你有数个对象的集合,它们之间有“整体/部分”的关系,并且你想用一致方式对待这些对象时,就可以使用组合模式。
第十章 状态模式
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
状态模式将状态封装成为独立的类,并将动作委托到代表当前状态的对象。从客户的视角来看:如果说你使用的对象能够完全改变它的行为,那么你会觉得,这个对象实际上是别的类实例化而来的,然而,实际上,你知道我们是使用组合通过简单引用不同的状态对象来造成类改变的假象。
策略模式和状态模式是双胞胎,他们的类图完全相同,只是各自的意图不同。策略模式是围绕可以互换的算法来创建成功业务的,而状态模式是通过改变对象内部的状态来帮助对象控制自己的行为。
以状态模式而言,我们将一群行为封装在状态对象中,context的行为随时可以委托到那些状态对象中的一个。随着时间的流逝,当前状态在状态对象集合中游走改变,以反映出context内部的状态,因此,context的行为也会跟着改变。但是context的客户对于状态对象了解不多,甚至根本是浑然不觉。
状态类会使设计中类的数目大量增加。
第十一章 代理模式(proxy)
代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。
使用代理模式创建代表(Representative)对象,让代表对象控制某对象的访问,被代理的对象可以是远程的对象,创建开销大的对象或需要安全控制的对象。
-远程代理控制访问远程对象(java中的RMI)
-虚拟代理控制访问创建开销大的资源(远程图片显示)
-保护代理基于权限控制对资源的访问
第十二章 复合模式(Compound)
-模式通常被一起使用,并被组合在同一个设计解决方案中。
-复合模式在一个解决方案中结合两个或多个模式,以解决一般或重复发生的问题。
示例:鸭子与鹅(适配器,迭代模式,观察者,抽象工厂,策略模式)
MVC:模型视图控制器(策略,观察者,组合模式)
第十三章 真实生活中的模式
-让设计模式自然而然地出现在你的设计中,而不是为了使用而使用。
-设计模式并非僵化的教条,你可以依据自己的需要采用或调整。
-总是使用满足需要的最简单解决方案,不管它用不用模式。
-学习设计模式的类目,可以帮你自己熟悉这些模式以及它们之间的关系。
模式的分类:
创建型,结构型与行为模式
创建型模式:抽象工厂模式,生成器模式,工厂方法模式,原型模式,单件模式
结构型模式: 适配器模式,桥接模式,组合模式,装饰者模式,外观模式,享元模式,代理模式
行为模式:职责链模式,命令模式,解释器模式,迭代器模式,中介者模式,备忘录模式,观察者模式,状态模式,策略模式,模板方法模式,访问者模式
类模式和对象模式
类模式:模板方法模式(Template method),工厂方法模式(Factory method),适配器模式(Adapter),解释器模式(Interpreter)
对象模式:组合模式(),访问者模式,外观模式,代理模式,策略模式,桥接模式,享元模式,抽象工厂模式,单件模式,迭代器模式,命令模式,备忘录模式,观察者模式,职责链模式,中介者模式,原型模式,生成器模式
总结:
装饰者模式:包装一个对象,以提供新的行为。
适配器模式:封装对象,并提供不同的接口。
模板方法模式:由子类决定如何实现一个算法中的步骤。
工厂方法模式:由子类决定要创建的具体类似哪一个。
单件模式:确保有且只有一个对象被创建。
策略模式:封装可以互换的行为,并使用委托来决定要使用哪一个。
组合模式:客户用一致的方式处理对象集合和单个对象。
状态模式:封装了基于状态的行为,并使用委托在行为之间切换。
迭代器模式:在对象的集合之中游走,而不是暴露集合的实现。
外观模式:简化一群类的接口。
装饰者模式:包装一个对象,以提供新的行为。
抽象工厂方法:允许客户创建对象的家族,而无需指定他们的具体类。
观察者模式:让对象能够在状态改变时被通知。
代理模式:包装对象,以控制对此对象的访问。
命令模式:封装请求成为对象。
附录A 剩余的模式
桥接模式(Bridge)
使用桥接模式不只改变你的实现,也改变你的抽象。桥接模式通过将实现和抽象放在两个不同的类层次中而使它们可以独立改变。
桥接的优点:
-将实现予以解耦,让它和界面之间不再永久绑定。
-抽象和实现可以独立扩展,不会影响到对方。
-对于“具体的抽象类”所做的改变,不会影响到客户。
桥接的用途和缺点:
-适合使用在需要跨越多个平台的图形和窗口系统上。
-当需要用不同的方法改变接口和实现时,你会发现桥接模式很好用。
-桥接模式的缺点是增加了复杂度。
示例:控制器与界面各自的抽象
生成器模式(Builder)
-使用生成器模式封装一个产品的构造过程,并允许按步骤构造。
生成器的优点:
-将一个复杂对象的创建过程封装起来。
-允许对象通过多个步骤来创建,并且可以改变过程(这和只有一个步骤的工程模式不同)。
-向客户隐藏产品内部的实现。
-产品的实现可以被替换,因为客户只看到一个抽象的接口。
生成器的用途和缺点:
-经常被用来创建组合结构
-与工厂模式相比,采用生成器模式创建对象的客户,需要具备更多的领域知识。
示例:度假计划
责任链模式(Chain of responsibility)
当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式。
责任链模式的优点:
-将请求的发送者和接受者解耦
-可以简化你的对象,因为它不需要知道链的结构
-通过改变链内的成员或调动它们的次序,允许你动态地新增或者删除责任
责任链的用途与缺点:
-经常被使用在窗口系统中,处理鼠标和键盘之类的事件
-并不保证请求一定会被执行;如果没有任何对象处理它的话,它可能会落到链尾之外(这可以是优点也可以是缺点)
-可能不容易观察运行时的特征,有碍于除错
示例:不同邮件(垃圾邮件,Fans邮件,客服邮件,业务邮件等)的处理
享元模式(Flyweight)
如想让某个类的一个实例能用来提供许多“虚拟实例”,就是用享元模式
享元模式的优点:
-减少运行时对象实例的个数,节省内存
-将许多“虚拟对象”的状态集中管理
享元模式的用途与缺点:
-当一个类有许多的实例,而这些实例能被同一方法控制的时候,我们就可以使用享元模式
-缺点:一旦你实现了它,那么单个的逻辑实例将无法拥有独立而不同的处理
享元模式
示例:景观设计中的点缀树的显示(只一个树实例,共享位置年轮信息)
解释器模式(Intepreter)
使用解释器模式为语言创建解释器
解释器的优点:
-将每一个语法规则表示成一个类,方便于实现语言
-将每一个语法规则表示成一个类,方便于实现语言
-因为语法由许多类表示,所以你可以轻易地改变或扩展此语言
-通过在类结构中加入新的方法,可以在解释的同时增加新的行为,例如打印格式的美化或者进行复杂的程序验证
解释器的用途与缺点:
-当你需要实现一个简单的语言时,使用解释器
-当你有一个简单的语法,而且简单比效率更重要时,使用解释器
-可以处理脚本语言和编程语言
-当语言规则的数码太大时,这个模式可能会变得相当繁杂,在这种情况下,使用解释器/编译器的产生器可能更合适
示例:Duck pond控制鸭子的语言解释器
中介者模式(Mediator)
使用中介者模式来集中相关对象之间复杂的沟通和控制方式。每个对象都会在自己的状态改变时,告诉中介者,每个对象都会对中介者所发出的请求作出反应。中介者内包含了整个系统的控制逻辑。当某个对象需要一个新的规则时,或者是一个新的对象被加入系统内,其所有需要用到的逻辑也都被加入中介者内。
中介者模式的优点:
-通过将对象彼此解耦,可以增加对象的复用性
-通过将控制逻辑集中,可以简化系统维护
-可以让对象之间所传递的消息变得简单而且大幅减少
中介者模式的用途和缺点:
-中介者模式常常被用来协调相关的GUI组件
-中介者模式的缺点是:如果设计不当,中介者对象本身会变得过于复杂
示例:生活自动机(闹铃,煮咖啡,日历,喷头)
备忘录模式(Memento)
当你需要让对象返回之前的状态时(例如:undo),就使用备忘录模式。备忘录模式有两个目标:储存系统关键对象的重要状态;维护关键对象的封装。请不要忘记单一责任原则,不要把保持状态的工作和关键对象混在一起,这样比较好。这个专门掌握状态的对象就称为备忘录。
备忘录模式的优点:
-被储存的状态放在外面,不要和关键对象混在一起,这可以帮助维护内聚
-保持关节对象的数据封装
-提供了容易实现的恢复能力
备忘录模式的用途和缺点:
-备忘录用于储存状态
-使用备忘录的缺点:储存和恢复状态的过程可能相当耗时
-在Java系统中,其实可以考虑使用序列化(Serialization)机制储存系统的状态
示例:游戏中的存储进度功能
原型模式(Prototype)
当创建给定类的实例的过程很昂贵或很复杂时,就使用原型模式。原型模式允许你通过使用复制现有的实例来创建新的实例(在Java中,这通常意味着使用clone()方法或者反序列化)。这个模式的重点在于,客户的代码在不知道要实例化何种特定类的情况下,可以制造出新的实例。
原型模式的优点:
-向客户隐藏制造新实例的复杂性
-提供客户能够产生未知类型对象的选项
-在某些环境下,复制对象比创建新对象更有效
原型模式的用途和缺点:
-在一个复杂的类层次中,当系统必须从其中的许多类型创建新对象时,可以考虑原型
-缺点:对象的复制有时相当复杂
示例:在游戏中创建各式各样的怪兽
访问者模式(Visitor)
当你想要为一个对象的组合增加新的能力,且封装并不重要时,就使用访问者模式。
客户要求访问者从组合结构中取得信息,新方法可以被加入到访问者中,而不会影响组合;访问者需要能够调用组合类的getState(),而这也正是你能够加入新方法以让客户使用的地方;所有的这些组合类必须做的事情就是加入一个getState()方法,而不必担心暴露他们自己。
访问者模式的优点:
-允许你对组合结构加入新的操作,而不需改变结构本身
-想要加入新的操作,相对容易
-访问者所进行的操作,其代码是集中在一起的
访问者模式的用途和缺点:
-当采用访问者模式的时候,就会打破组合类的封装
-因为游走的功能牵涉其中,所以对组合结构的改变就更加困难
示例:对乡村餐厅的菜单添加营养成分,能量显示