文章目录
- 设计模式
- 1 策略模式 Strategy
- 2 观察者模式 Observer
- 3 装饰者模式 Decorator
- 4 工厂方法模式 Factory Method
- 5 抽象工厂模式 Abstract Factory
- 6 单件模式 Singleton
- 7 命令模式 Command
- 8 适配器模式 Adapter
- 9 外观模式 Facade
- 10 模板方法模式 Template Method
- 11 迭代器模式 Iterator
- 12 组合模式 Composite
- 13 状态模式 State
- 14 代理模式 Proxy
- 15 桥接模式 Bridge
- 16 生成器模式 Builder
- 17 责任链模式 Chain of Responsibility
- 18 蝇量模式 Flyweight
- 19 解释器模式 Interpreter
- 20 中介者 Mediator
- 21 备忘录 Memento
- 22 原型 Prototype
- 23 访问者 Visitor
- 24 复合模式 Compound
设计模式
高内聚:当一个模块或一个类被设计成只支持一组相关的功能时,就是高内聚
低耦合:降低不同类之间的耦合程度,牵一发动全身的程度
- 将代码中可能变化的部分单独封装出来
- 针对接口编程,而不是针对实现编程
- 多用组合,少用继承
- 为了交互对象之间的松耦合设计而努力
- 类应该对扩展开放,对修改关闭
- 要依赖抽象,不要依赖具体类(变量不可以持有具体类行为,不要让类派生自具体类,不要覆盖基类已实现的方法)
- 最少知识原则,减少对象之间交互(只应该调用属于以下范围的方法,该对象本身,被当作方法的参数传递进来的对象,此方法所创建或实例化的对象,对象的任何组件)
- 别调用我们,我们会调用你(允许低层组件将自己挂钩到系统上,但高层组件决定什么时候和怎样使用低层组件)
- 单一责任(一个类应该只有一个引起变化的原因,类的每个责任都有改变的潜在区域,超过一个责任,意味着超过一个改变的区域)
在设计模式中,“实现一个接口”泛指“实现某个超类或者接口的某个方法”
模式分类
策略模式:封装可以互换的行为,并使用委托来决定要使用哪一个
观察者模式:让对象能够在状态改变时被通知
装饰者模式:包装一个对象,以提供新的行为
工厂方法模式:由子类决定要创建的具体类是哪一个
抽象工厂模式:允许客户创建对象的宗族,而无需指定他们的具体类
单件模式:确保有且只有一个对象被创建
命令模式:封装请求成为对象
适配器模式:封装对象,并提供不同的接口
外观模式:简化一群类的接口
模板方法模式:由子类决定如何实现一个算法中的步骤
迭代器模式:在对象的集合之中游走,而不暴露集合的实现
组合模式:客户用一致的方式处理对象集合和单个对象
状态模式:封装了基于状态的行为,并使用委托在行为之间切换
代理模式:包装对象,以控制对此对象的访问
1 策略模式 Strategy
定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户
2 观察者模式 Observer
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新
“一个”主题对“多个”观察者
观察者模式提供了一种设计模式,让主题和观察者之间松耦合
主题唯一依赖的东西是一个实现Observer接口的对象列表,所以我们可以随时增加观察者
主题不在乎别的,它只会发送通知给所有实现了观察者接口的对象
Java内置的观察者模式
java.util包含Observer接口和Observable类,Observable类是类不是接口
可观察者送出通知:先调用setChanged(),标记状态已经改变;然后调用notifyObservers()或notifyObservers(Object arg)
观察者收到通知:可观察者的notify中调用了观察者的update(Observable o, Object arg),将可观察者对象传过去,由观察者自行获取数据
如果调用notify之前没有调用setChanged,则观察者不会被通知
内置观察者模式的缺点:Observable是一个类,Java不支持多重继承,限制了Observable的复用潜力
3 装饰者模式 Decorator
动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更由弹性的替代方案
图中用超类使得装饰者和被装饰者同类型,可以用接口
- 装饰者和被装饰对象有相同的超类型
- 可以用一个或多个装饰者包装一个对象
- 装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为
- 对象可以在任何时候被装饰,可以在运行时动态的装饰对象
装饰者模式缺点:常常造成设计中有大量的小类,数量多,可能会造成使用此API程序员的困扰
Java.io的装饰者模式
4 工厂方法模式 Factory Method
工厂处理创建对象的细节
定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类
静态工厂:用静态方法定义一个简单的工厂,不需要使用创建对象的方法实例化对象,但也不能通过继承来改变创建对象方法的行为
简单工厂:工厂通常只有一个静态方法,可以通过传入字符串,选择要实例化的具体对象
工厂方法
简单工厂把全部事情都在一个地方处理完了,然而工厂方法却是创建一个框架让子类决定如何实现
5 抽象工厂模式 Abstract Factory
工厂处理创建对象的细节
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类
在抽象工厂中利用工厂方法实现生产方法
6 单件模式 Singleton
确保一个类只有一个实例,并提供一个全局访问点
多线程
- 对getInstance方法增加synchronized关键字,但同步会带来额外的开销
- 改善:如果该方法的性能影响不大,则无所谓开销
- 改善:如果总是调用该方法,则不用延迟实例化
- 改善:双重检查加锁,如果uniqueInstance没有创建,则使用同步,同步中再判断一次
7 命令模式 Command
将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作
一个命令对象通过在特定接收者上绑定一组动作来封装一个请求。命令对象将动作和接收者包进对象中。这个对象只暴露出一个execute方法,当此方法被调用时,接收者就会进行这些操作
8 适配器模式 Adapter
将一个类的接口,转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以合作无间
实现一个适配器所需要进行的工作和目标接口的大小成正比
类适配器(Java不支持多重继承)
9 外观模式 Facade
提供了一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层接口,让子系统更容易使用
外观不只是简化了接口,也将客户从组件的子系统中解耦
外观和适配器可以包装许多类,但是外观的意图是简化接口,而适配器的意图是将接口转换成不同接口
10 模板方法模式 Template Method
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤
模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现
在模板方法中使用钩子,钩子是一种被声明在抽象类中的方法,但只有空或者默认实现。需不需要挂钩由子类决定
策略模式和模板模式都封装算法,一个用组合,一个用继承
11 迭代器模式 Iterator
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示
把游走的任务放在迭代器上,而不是聚合上,这样简化了聚合的接口和实现,也让责任各得其所
12 组合模式 Composite
允许你将对象组合成树形结构来表现“整体/部分”层次结构,组合能让客户以一致的方式处理个别对象以及对象组合
使用组合结构,我们能把相同的操作应用在组合和个别对象上,换句话,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别
组合模式以单一责任设计原则换取透明性,客户可以将组合和叶子节点一视同仁
13 状态模式 State
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类
状态模式将状态封装成独立的类,并将动作委托到代表当前状态的对象,行为会随着内部状态而改变
状态模式将一群行为封装在状态对象中,客户对于状态对象了解不多
策略模式中,客户通常主动指定组合的策略对象
14 代理模式 Proxy
为另一个对象提供一个替身或占位符以控制对这个对象的访问
使用代理模式创建代表对象,让代表对象控制某对象的访问,被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象
14.1 动态代理
java.lang.reflect包,由于实际代理类是在运行时创建的,所以称为动态代理
Proxy本身是利用静态的Proxy.newProxyInstance()创建的,实际的运行逻辑写在InvocationHandler中
Proxy.newProxyInstance(people.getClass().getClassLoader(),
people.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(people.getClass().getName());
method.invoke(people, args);
return null;
}
});
14.2 远程代理
远程代理可以作为另一个JVM上对象的本地代理。调用代理的方法,会被代理利用网络转发到远程执行,并且结果会通过网络返回给代理,再由代理将结果转给客户
远程调用:客户调用客户辅助对象的方法,仿佛就是真的对象;客户辅助对象联系服务器;服务辅助对象接收请求,调用真实服务对象
Java RMI:提供了客户辅助对象和服务辅助对象,客户辅助对象称为stub,服务辅助对象称为skeleton,Java1.2摆脱了skeleton,Java5不需要stub,stub通过java.lang.reflect.Proxy实例自动产生
步骤:1)制作远程接口,stub和实际服务都实现此接口;2)制作远程实现,返回的类型必须是可序列化的类型;3)利用rmic产生stub和skeleton;4)启动rmiregistry;5)注册远程服务;6)客户通过Naming.lookup(“rmi://127.0.0.1/RemoteHello”)取得服务对象
14.3 虚拟代理
虚拟代理作为创建开销大的对象的代表。虚拟代理经常直到我们真正需要一个对象的时候才创建它。当对象在创建前和创建中时,由虚拟代理来扮演对象的替身。对象创建后,代理就会将请求直接委托给对象
保护代理:根据访问权限决定客户可否访问对象的代理
防火墙代理:控制网络资源的访问,保护主题免于侵害
智能引用代理:当主题被引用时,进行额外的动作,例如计算一个对象被引用的次数
缓存代理:为开销大的运算对象提供暂时存储;它允许多个客户共享结果,以减少计算或网络延迟
同步代理:在多线程的情况下为主题提供安全的访问
复杂隐藏代理:用来隐藏一个类的复杂集合的复杂度,并进行控制访问
写入时复制代理:用来控制对象的复制,方法时延迟对象的复制,直到客户真的需要为止,这是虚拟代理的变体
15 桥接模式 Bridge
通过将实现和抽象放在两个不同的类层次中而使他们可以独立改变
16 生成器模式 Builder
封装一个产品的构造过程,并允许按步骤构造
17 责任链模式 Chain of Responsibility
使用一个以上的对象有机会能够处理某个请求
18 蝇量模式 Flyweight
让某个类的一个实例能用来提供许多“虚拟实例”
19 解释器模式 Interpreter
为语言创建解释器
20 中介者 Mediator
集中相关对象之间复杂的沟通和控制方式
21 备忘录 Memento
需要让对象返回之前的状态时
22 原型 Prototype
当创建给定类的实例的过程很昂贵或很复杂时
23 访问者 Visitor
为一个对象的组合增加新的能力
24 复合模式 Compound
复合模式在一个解决方案中结合两个或多个模式,以解决一般或重复发生的问题
例如:MVC,1)策略模式:视图是一个对象,控制器提供了策略,策略模式让视图和模型解耦;2)组合模式:视图显示了包括窗口、面板等;3)观察者模式:当模型的状态改变时,视图和控制器可知