设计模式原则:
依赖倒置原则,单一职责原则,迪米特原则,里氏代换,开闭原则,高内聚,松耦合原则
第一章:策略模式
OO基础:抽象、封装、多态、继承
OO原则:封装变化、多用组合,少用继承、针对接口编程,不针对实现编程
OO模式:策略模式——定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户
要点: 1 知道OO基础,并不足以让你设计出良好的OO系统
2 良好的OO设计必须具备可复用,可扩充,可维护三个特性
3 模式可以让我们建造出具有良好OO设计质量的系统
4 模式被认为是历经验证的OO设计经验
5 模式不是代码,而是针对设计问题的通用解决方案,你可以把它们应用到特定的应用中
6 模式不是被发明,而是被发现
7 大多数的模式和原则,都着眼于软件变化的主题
8 大多数的模式都允许系统局部改变独立于系统其他部分
9 我们常把系统中会变化的部分抽出来封装
10 模式让开发人员之间有共享的语言,能够最大化沟通的价值
(采用组合)
第二章:观察者模式
OO原则:为交互对象之间的松耦合设计而努力,松耦合设计更有弹性,更能应对变化
OO模式:观察者模式——在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新;一个新的模式,以松耦合方式在一系列对象之间沟通状态,例如:监听器,MVC等等
要点:
1 观察者模式定义了对象之间一对多的关系
2 主题(也就是可观察者)用一个共同的接口来更新观察者
3 观察者和可观察者之间用松耦合方式结合,可观察者不知道观察者的细节,只知道观察者实现了观察者接口
4 使用此模式时,你可以从被观察者处推(push)或拉(pull)数据(然而,推的方式被认为更“正确”)。
5 有多个观察者时,不可以依赖于特定的通知次序。
6 Java有多种观察者模式的实现,包括了通用的Java.util.Observable。
第三章:装饰器模式
OO原则:对扩展开放,对修改关闭(开闭原则)
OO模式:装饰器模式——动态的将责任附加到对象上,想要扩展功能,装饰者提供有别于继承的另一种选择。
要点:
1 继承属于扩展形式之一,但不见得是达到弹性设计的最佳方案。
2 在我们的设计中,应用允许行为可以被扩展,而无须修改现有的代码
3 组合和委托可用于在运行时动态地加上新的行为。
4 装饰者类反映出被装饰的组件类型(事实上,他们具有相同的类型,都经过接口或继承实现)
5 装饰者可以在被装饰者的行为前面或者后面加上自己的行为,甚至将被装饰者的行为替换掉,而达到特定的目的。
6 你可以用无数个装饰者包装一个组件。
7 装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得复杂。
第四章:工厂模式
OO原则:依赖倒置原则(要依赖抽象,不要依赖具体实现)
OO模式:工厂方法模式——定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。
抽象工厂模式——提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
这些信的模式可以将对象的创建工作封装起来,以便于得到更加松耦合,更有弹性的设计。
要点:
1 工厂方法使用继承,把对象的创建委托给子类,子类实现工厂方法来创建对象。
2 抽象工厂使用对象组合,对象的创建被实现在工厂接口所暴露出来的方法中。
第五章:单例模式
OO模式:单例模式——确保一个类只有一个实例,并提供全局访问点。
1 在Java中实现单例模式需要私有的构造器,一个静态方法,一个静态变量。
2 确定在性能和资源上的限制,然后小心的选择适当的方案来实现单例,以解决多线程的问题。
单例模式多线程安全时的解决方案:
1 采用加锁的方式
public static T getInstance(){
synchronized(obj){ //这样做的不好的地方就是每次调用都要进行加锁,这样就导致性能下降;
if(instance == null){
instance = new T();
}
}
return instance;
}
改进方式:
public static T getInstance(){
if(instance == null){
synchronized(obj){
if(instance == null){ //思考:为何这里要再次判断instance是否为null;
instance = new T();
}
}
}
return instance;
}
2 采用静态初始化的方式:类加载的时候就初始化,依据final类只会加载,初始化一次,就可以保证单例类的“单例”性质了。
public final class T{ //思考:为啥必须是final类?
public static T instance = new T();
private T() {}
public static T getInstance(){
return instance;
}
}
第六章:命令模式
OO模式:命令模式——将请求封装成对象,这可以让你使用不同的请求,队列,或者日志请求来参数化其他对象。命令模式也可以支持撤销操作。当需要将发出请求的对象和执行请求的对象解耦的时候,使用命令模式。
要点:
1 命令对象封装了接收者和一个或一组动作
第七章:适配器模式,外观模式
OO原则:最少知识原则,只和朋友交谈,一个方法可以调用本对象的方法,可以调用作为参数传进来的对象的方法,可以调用本对象中实例变量对象的方法,可以调用本方法中实例化的对象的方法,不能调用由调用方法返回的结果对象中的方法。
OO模式:
适配器模式——将一个类的接口,转换成客户期望的另一接口。
外观模式——提供了一个统一的接口,用来访问子系统中一群接口,外观定义了一个高层接口,让子系统更容易使用。
第八章:模板方法模式
OO原则:好莱坞原则,你别找我,我会来找你(底层组件不要依赖高层组件,高层组件依赖底层组件)
OO模式:模板方法模式——在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
要点:
1 模板方法的抽象类可以定义具体的方法,抽象方法,和钩子。
2 好莱坞原则告诉我们,将决策权放在高层模块中,以便决定如何以及何时调用低层模块。
3 工厂方法是模块方法的一个特殊版本。
第九章:迭代器和组合模式
OO原则:类应该只有一个改变的理由
OO模式:
迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
组合模式:允许你将对象组成树形结构来表现“整体/部分”的层次结构,组合能让客户以一致的方式处理个别对象和对象组合。
要点:
1 迭代器允许访问聚合的元素,而不需要暴露它的内部结构
2 迭代器将遍历聚合的工作封装进一个对象中
3 当使用迭代器的时候,我们依赖聚合提供遍历
4 迭代器提供了一个通用的接口,让我们遍历聚合的项,当我们编码使用聚合的项时,就可以使用多态机制
5 我们应该努力让一个类只分配一个责任
6 组合模式提供一个结构,可同时包容个别对象和组合对象
7 组合模式允许对个别对象和组合对象一视同仁
8 组合结构内的任意对象称为组件,组件可以是组合,也可以是叶节点
9 在实现组合模式时,有许多设计上的折中,你要根据需要平衡透明性和安全性。
第十章:状态模式
OO模式:允许对象在内部状态改变的时候改变它的行为,对象看起来好像修改了它的类。
要点:
1 状态模式允许一个对象基于内部状态二拥有不同的行为
2 和程序状态机不同,状态模式用类代表状态
3 Context会将行为委托给当前状态对象
4 通过将每个状态封装进一个类,我们把以后需要做的任何改变局部化了
5 状态模式和策略模式有相同的类图,但是它们的意图不同
6 策略模式通常会用行为或者算法来配置Context类
7 状态模式允许Context随着状态的改变而改变行为
8 状态转换可以由State类或Context类控制
9 使用状态模式通常会导致设计中类的数目大量增加
10 状态类可以被多个Context类共享。
第十一章:代理模式
OO模式:代理模式——为另一个对象提供一个替身或占位符以访问这个对象。
要点:
1 代理模式为另一个对象提供代表,以便控制客户对对象的访问,管理访问的方式有许多种
2 远程代理管理客户和远程对象之间的交互
3 虚拟代理控制访问实例化开销大的对象
4 保护代理基于调用者控制对对象方法的访问
5 代理模式有许多变体:例如:缓存代理,同步代理,防火墙代理等等
6 代理在结构上类似装饰者,但是目的不同
7 装饰者模式为对象加上行为,而代理则是控制访问
第十二章:复合模式
看完《大话设计模式》,对访问者模式印象很深,因为自己无意中也算是用到了这个模式,只是用的时候未曾意识到自己是用到了这个模式(更当初使用观察者模式时候一样:))
访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
这句话是书中的原话,不免有些绕口和晦涩难懂,我的理解就是:我们在定义类的时候,就会有类的属性,以及类的行为,其中不乏有些是针对属性操作的行为,这里可以把属性理解为数据结构,这些行为理解为操作。当出现一种情况:数据结构比较固定,但是操作却是动态更新和变化的时候,就可以考虑使用访问者模式,因为它承诺:在不改变类的前提下,可以定义作用于这些类中的元素的操作,也就是在坚持开闭原则的情况下对代码做扩展,那么它是怎么样做到这一点的呢?
它就是采用了“双委派”机制,也就是delegate两次。具体如下:
public class Data{
//some data
public void action(Action action){ //这里是第一次delegate
action.performAction(this);
}
}
public class Action{
public void performAction(Data data){ //这里是第二次delegate
//针对data中的元素做一些操作。
}
}
客户端代码略。
这个就是我的理解,当然我没有在这里做出抽象层来,但是访问者模式的核心思想应该是这样的,欢迎指正!