(二)结构型
结构型模式 讨论的是 类和对象的结构,通过继承机制来组合接口,实现一些新的功能。
结构性 模式分为7种。分别是代理模式、装饰模式、适配器模式、组合模式、桥梁模式、外观模式和享元模式。
速记口诀:桥代理组合适配器,享元回家装饰外观。解释:有个姓桥的代理组装适配器,他儿子享元拿回家装饰外观去啦
1. 桥梁模式
定义:将抽象(Abstraction)和实现(Implementor)解耦。使得两者可以独立的变化。
两个类之间的关系分为两种。强关联和弱关联。强关联是指在编译的时候就已经确定。若关联是指在运行时期动态的改变。相比之下,弱关联更加灵活。脱耦其实就是将强关联修改为弱关联。
桥梁模式设计4个角色。分别是 抽象化角色、实现化角色、修正抽象化角色和具体实现化角色。
(1) 抽象化角色
抽象化的定义,并且保存一个对实现化的引用。
(2) 实现化角色
实现化角色的接口
(3) 修正抽象化角色(抽象类)
扩展抽象化角色(抽象化的具体实现),引用实现化角色并对抽象化橘色进行修正。
(4) 具体抽象化角色
具体抽象角色 继承 修正抽象类,复写业务方法(使用引用的实现化对象(实现化有多种N,此处引用一种)和自身的抽象化(抽象化实现有多种M,此处为一种),达到M*N的组合结果。
2. 代理模式
定义:通过代理对象,以达到控制访问对这个类的访问。
代理分为3个角色:抽象主题、具体主题和真实代理。
(1) 抽象主题:
被代理对象的接口。
(2) 具体主题:
被代理的对象。实现了抽象主题。
(3) 真实代理:
核心理解:实现抽象主题(接口),同时依赖主题接口对象。
实现抽象主题:因为 真实代理实现了抽象主题的接口,所以,真实代理 也有抽象主题中的方法。所以,可以对外提供抽象主题的方法。从表面看,真实代理也可以完成抽象主题中定义的方法。
依赖抽象主题(自己不能实现主题的方法,通过依赖具体主题,来实现方法):真实代替因为依赖了抽象主题的接口对象。一般通过真实代理的构造方法传递具体代理。而在真实代理中对抽象主题方法实现的时候,是通过依赖的具体主题来实现的。
客户端在实现代替对象方法前后,添加自己方法:在真实代理中,一般会定义before 方法和 after 方法。然后在调用代理方法的前后,可以添加客户端定义的准备方法和善后方法。
3. 组合模式
定义:组合用来描述部分和整体的关系。
使用在特殊的 场景之下。一组对象有功能的接口。且现实中有层次结构。
组合模式涉及以下几个角色;抽象构件、叶子构件和树枝构件。
(1) 抽象构件
定义一组对象公有的方法和属性。
(2) 叶子构件
实现抽象构件,但是向下没有其他分支。
(3) 树枝构件
向下有分支的树枝对象。
树枝构件稍稍复杂一点:有 构件容器 保存向下的分支、叶子。构件容器一般为ArrayList。对应的有添加、删除、返回操作。对应方法add、remove、getChildren。因为实现了抽象构件,所以也有抽象构件定义的方法。Operation。
Add:list.add
Remove:list.remove
getChildren:return list
Operation:抽象构件定义的具体方法实现。
在客户端:通过组合模式的层次关系可以组成一个树形结构。通过递归的display方法可以遍历所有元素。
Public void display ( composite root){
For(Composite e: root.getChildren){
If(e: instanceoOf leaf ){
e.operation()
}else {
e.operation()
Display(e)
}
}
}
4. 适配器模式
定义:将一个类的一个接口转换成客户端所期待的另外一种接口。
理解:本质是一种转换,将原有的功能转换成新的功能并对外提供使用。生活中有很多类似的例子。两孔的插线口转成3孔的插线板。或者在旧系统改造升级的时候,使用旧的类加工转换成新的接口对外提供使用。
适配器涉及以下几个角色。目标、源和适配器。
(1) 目标:target
客户端所期待的接口。定义目标方法。
一般就是一个接口。
(2) 源:adaptee
需要被转换成目标的对象。
(3) 适配器:adaptor
通过继承或者类关联的方式,将源的功能转换成目标方法。
依赖源:通过继承或者类关联的方式。依赖源adaptee。
实现接口 目标target:实现接口target方法。在方法中核心是调用源adaptee的原有方法,做转换。完成target方法。对外提供新的接口方法。
5. 享元模式
定义:享元模式实现共享对象,是池技术的重要实现方式。
享元技术能实现的关键是 区分内部状态Internal state和外部状态external state。内部状态是享元内部的状态,可以共享的信息,唯一确定一个享元的信息。外部信息是不可共享的信息。外部信息是客户端自己保存。在享元创建后,在使用的时候,在闯入享元对象的内部。
享元模式可以分为以下4个角色。抽象享元角色、具体享元角色、享元工厂角色和客户端角色。
(1) 抽象享元角色
对享元进行抽象,抽象方法需要传入外部参数(内部参数在享元创建的时刻就已经在享元内部包含)。
(2) 具体享元角色
实现抽象享元。需要有内部参数属性。Internal_state .
构造方法:享元的构造方法需要传递内部参数。
业务方法:业务方法需要传递外部参数。因为内部参数为享元内部属性。所以在享元业务方法中,既可以使用内部属性参数,也可以使用外部属性参数。
(3) 享元工厂角色
该角色就是构造一个池容器。是单例实现。
- 池对象私有且静态。
Private static Map<string,flyweight> pool = new HashMap<>()
- 构造方法私有
Private FlyweightFactory (){}
- 对外提供 获取享元 静态方法,。
Public static getFlyWeight(String internal_state){
flyWeight = pool.get( internal_state);
If(flyWeight == null){
flyWeight = new flyWeight (internal_state)
Pool.put(internal_state,flyWeight )
}
Return flyWeight ;
}
(4) 客户端角色
需要存储所有享元的外部状态。
6. 装饰模式
定义:动态的给一个类添加额外的职责。在抽象构件的方法上装饰新的功能。和代理模式极其类似。
装饰模式分为4个角色。抽象构件、具体构件、装饰角色和具体装饰。
(1) 抽象构件:
需要装饰的对象的抽象。
(2) 具体构件:
需要装饰的类。
(3) 装饰者:
实现抽象构件 且 依赖抽象构件的对象。 装饰着需要实现的方法(抽象构件中定义的方法)由依赖的具体构件实现。
备注:和代理模式特别相似。只是,没有添加装饰。
(4) 具体装饰者:
通过继承 装饰者,重写构件方法。在方法前后可以添加需要装饰的额外职责。
7. 外观模式
定义:要求一个子系统,外部和其内部进行通信,需要通过一个统一的对象进行交互。Facade。
外观模式是一种简单的变成思想。
子系统将所有的功能引用封装到一个门面facade中。外部系统需要和子系统通信,需要对facade引用。