1. Adapter(适配器)
将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,别名包装器(Wrapper)。
如非必要,可以重构
模式应用
- Enumeration 接口转化为 Iterator 接口
- Java I/O中
InputStreamReader
和OutputStreamWriter
待适配
待适配
public class Source {
public void method1() {}
}
目标接口
public interface Targetable {
/* 与原类中的方法相同 */
public void method1();
/* 新类的方法 */
public void method2();
}
1 类的适配器模式
Adapter 类继承 Source 类,实现 Targetable 接口
public class Adapter extends Source implements Targetable {
@Override
public void method2() {
System.out.println("this is the targetable method!");
}
}
2 对象的适配器模式
持有 Source 类的实例
public class Wrapper implements Targetable {
private Source source;
public Wrapper(Source source){
super();
this.source = source;
}
@Override
public void method1() {
source.method1();
}
@Override
public void method2() {
System.out.println("this is the targetable method!");
}
}
3 接口的适配器模式
不希望实现一个接口中所有的方法时,通过抽象类实现该接口,再继承抽象类
public abstract class Wrapper2 implements Targetable{
public void method1(){}
public void method2(){}
}
public class SourceSub1 extends Wrapper2 {
public void method1(){
System.out.println("the sourceable interface's first Sub1!");
}
}
2. Bridge(桥接)
将类的功能层次结构和实现层次结构相分离,使二者能够独立地变化,并在两者之间搭建桥梁,实现桥接。
- 类的功能层次结构:父类具有基本功能,在子类中增加新的功能;
- 类的实现层次结构:父类通过声明抽象方法来定义接口,子类通过实现具体方法来实现接口;
模式应用
- 抽象的 JDBC 接口和各个数据库引擎 API 之间的驱动程序
实现
1.桥接接口,实体类 RedCircle、GreenCircle 实现了 DrawAPI 接口
public interface DrawAPI {
public void drawCircle(int radius, int x, int y);
}
2.使用桥接的抽象类
public abstract class Shape {
protected DrawAPI drawAPI;
protected Shape(DrawAPI drawAPI){
this.drawAPI = drawAPI;
}
public abstract void draw();
}
3.抽象类的实体类。
public class Circle extends Shape {
private int x, y, radius;
public Circle(int x, int y, int radius, DrawAPI drawAPI) {
super(drawAPI);
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw() {
drawAPI.drawCircle(radius,x,y);
}
}
4.使用
Shape redCircle = new Circle(100,100, 10, new RedCircle());
Shape greenCircle = new Circle(100,100, 10, new GreenCircle());
redCircle.draw();
greenCircle.draw();
3. Composite(组合)
将对象组合成树形结构来表示“整体/部分”层次关系,允许用户以相同的方式处理单独对象和组合对象。
组件(Component)类是组合类(Composite)和叶子类(Leaf)的父类,可以把组合类看成是树的中间节点。
组合对象拥有一个或者多个组件对象,因此组合对象的操作可以委托给组件对象去处理,而组件对象可以是另一个组合对象或者叶子对象。
- 透明模式:在 component 中声明管理子对象的所有方法
- 安全模式:在 composite 中声明管理子对象的所有方法
4. Decorator(装饰器)
向一个现有的对象添加新的功能,同时又不改变其结构。
模式应用
JAVA IO 中 FilterInputStream
实现
装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰者之上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件的方法实现不需要依赖于其它对象。
适配器模式与装饰器模式的区别
装饰器与适配器都有一个别名叫做 包装模式(Wrapper),它们看似都是起到包装一个类或对象的作用,但是使用它们的目的很不一一样。适配器模式的意义是要将一个接口转变成另一个接口,它的目的是通过改变接口来达到重复使用的目的。
而装饰器模式不是要改变被装饰对象的接口,而是恰恰要保持原有的接口,但是增强原有对象的功能,或者改变原有对象的处理方式而提升性能。所以这两个模式设计的目的是不同的。
5. Facade(外观)
为子系统中的一组接口提供一个一致的界面,定义了一个高层接口,这个接口使得这一子系统更加容易使用。又称为门面模式。
6. Flyweight(享元)
运用共享技术有效地支持大量细粒度的对象。
工厂类、享元池
享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。
区分内部状态和外部状态
- 内部状态:存储在享元对象内部并且不会随环境改变而改变的状态,可以共享;
- 外部状态:随环境改变而改变的、不可以共享的状态。
模式应用
- JAVA 中的 String,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面。
- 数据库的数据池。
7. Proxy(代理)
给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
模式应用
- 远程代理:为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中。
- 虚拟代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
- Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。
- 保护代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
- 缓冲代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
- 防火墙代理:保护目标不让恶意用户接近。
- 同步化代理:使几个用户能够同时使用一个对象而没有冲突。
- 智能引用代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。
- 动态代理:Spring AOP、CGLIB
和适配器、装饰器的区别
- 和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
- 和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
8. Filter(过滤器)
允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。
模式应用
java8 的 stream 分组操作
Map<Integer, List<Person >> groupMap = persons.stream().collect(Collectors.groupingBy(Person::getGender));