结构型模式
- 核心作用:是从程序上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题。
- 分类:适配器模式、代理模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、
适配器模式
什么是适配器模式
- 将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
模式中的角色
- 目标接口(target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
- 需要适配的类(adaptee):需要适配的类或适配者类。
- 适配器(Adapter):需要包装一个需要适配的对象,把原接口转换成目标接口。
对象适配器通过组合的方式,实现需要适配的类中的方法
代理模式 (Proxy pattern)
核心作用
- 通过代理,控制对对象的访问
- 可以详细控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。(既:AOP的微观实现)
核心角色
- 抽象角色
- 定义代理角色和真实角色的公共对外方法
- 真实角色
- 实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色使用。
- 关注真正的业务逻辑!
- 代理角色
- 实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作
- 将统一的流程控制放到代理角色中处理
应用场景
- 安全代理:屏蔽对真实角色的直接访问。
- 远程代理:通过代理类处理远程方法调用(RMI)
- 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。
比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有100MB,在打开文件时不可能将所有的图片都显示出来,这样就可以 使用代理模式,当需要查看图片时,用proxy
分类
- 静态代理(静态定义代理类);
- 动态代理(动态生成代理类)
- JDK自带的动态代理
- javaassist字节码操作库实现
- CGLIB
- ASM(底层使用指令,可维护性较差)
静态代理(static proxy)
静态代理(静态定义代理类)
star:抽象角色
realstar:真实角色
proxyStar:代理角色
动态代理(dynamic proxy)
动态代理相比于静态代理的优点
- 抽象角色中(接口)声明的所有方法都被转移到调用器一个集中的方法中处理。这样我们可以更加灵活和统一的处理众多的方法。
JDK自带的动态代理
- java.lang.reflect.Proxy:动态生成代理类和对象
- java.lang.reflect.InvocationHandler(处理器接口)
- 可以通过invoke方法实现对真实角色的代理访问
- 每次通过Proxy生成代理类对象对象时都要指定对应的处理器对象
桥接模式
桥接模式核心要点
- 处理多层继承结构,处理多维度变化的场景,将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关联。
抽象出电脑品牌和电脑类型两个维度,两个维度独立可以扩展。
桥接模式总结
- 桥接模式可以取代多层继承的方案。多层继承违背单一职责原则,复用性较差,类的个数也非常多。桥接模式可以极大的减少子类的个数,从而降低管理和维护的成本。
- 桥接模式极大的提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有的系统,符合开闭原则。
组合模式
使用组合模式的场景
- 把部分和整体的关系用树形结构来表示,从而使客户端可以使用统一的方式处理部分对象和整体对象。
组合模式的核心
- 抽象构件(Component)角色: 定义了叶子和容器构件的共同点
- 叶子(Leaf)构件角色:无子节点
- 容器(Composite)构件角色: 有容器特征,可以包含子节点
组和模式工作流程
- 组和模式为处理树形结构提供了完美的解决方案, 描述了如何将容器和叶子进行递归组和,使得用户在使用时可以一致性的对待容器和业叶子。
- 当容器对象的指定方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员,并调用执行。其中,使用了递归调用的机制对整个结构进行处理。
装饰模式(decorator)
职责
- 动态的为一个对象增加新的功能
- 装饰模式是一种用于代替继承的技术,无须通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。
实现细节
- Component抽象构建角色
- 真实对象和装饰对象有相同的接口。这样,客户端对象就能够以与真实对象相同的方式同装饰对象交互
- ConcreteCompant具体构建角色(真实对象)
- io流中的FileInputStream、FileOutputStream
- Decorator装饰角色
- 持有一个抽象构件的引用。 装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象。这样,就能在真实对象调用前后增加新的功能。
- ConcreteDecorator具体装饰角色
- 负责给构件对象增加新的责任。
总结
- 装饰模式(Decorator)也叫包装器模式(Wrapper)
- 装饰模式降低系统的耦合度,可以动态的增加或删除对象的职责,并使得需要装饰的具体构建类和具体装饰类可以独立变化,以便增加新的具体构建类和具体装饰类
优点
- 扩展对象功能,比继承灵活,不会导致类个数急剧增加
- 可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象
- 具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类。
缺点
- 产生很多小对象。大量小对象占据内存,一定程度上影响性能。
- 装饰模式易于出错,调试排查比较麻烦
装饰模式和桥接模式的区别
- 两个模式都是为了解决过多子类对象问题。但他们の诱因不一样。桥模式是对象自身现有机制沿着多个维度变化,是既有部分不稳定。装饰模式是为了增加新的功能。
外观模式 facade
外观模式核心
- 为子系统提供统一的入口。封装子系统的复杂性,便于客户端使用。
享元模式 FlyWeight
享元模式实现
- FlyweightFactory 享元工产类
- 创建并管理享元对象,享元池一般设计成键值对。
- FlyWeight 抽象享元类
- 通常是一个接口或抽象类,声明公共方法,这些方法可以向外界提供对象的内部状态,设置外部状态。
- ConcreteFlyWeight 具体享元类
- 为内部状态提供成员变量进行存储
- UnsharedConcreteFlyWeight 非共享享元类
- 不能被共享的子类可以设计为非共享享元类、
享元模式实现的UML图
优点
- 极大的减少了内存中对象的数量
- 相同或相似对象内存中只存一份,极大的节约了资源,提高了系统性能
- 外部状态相对独立,不影响内部状态
缺点
- 模式较复杂,使程序逻辑复杂化
- 为了节省内存,共享了内部状态,分离出外部状态,而读取外部状态使运行时间变长。用时间换取了空间。