接着上一篇,创建型设计模式我们介绍了单例模式,简单工厂模式,抽象工厂模式,原型模式,建造者模式。接下来看看结构性模式。
二、结构型模式
顾名思义,结构型模式时从类的结构上来划分的,可以分为:适配器模式、装饰者模式、外观模式、享元模式、桥接模式、组合模式、代理模式(静态代理和动态代理)七种。
适配器模式
此模式相当于一个转接器,将两个不合适的接口连接起来使之能工作顺畅。比如一个水龙头要接一段水管,但是现有的水管并不符合水龙头的接口大小,因此就需要一个连接水龙头和水管的接口转换器。
将一个接口转为用户希望的另一个接口。
应用场景为:
1.现有的接口或类不满足需要,因此设计一个适配器来做转换,通过适配器间接地去访问那个接口和类;
2.当想要实现的一个接口方法太多时可以新建一个抽象类作为适配器,实现这个接口的所有方法,然后对外只暴露想要用到的方法。
image.png
装饰者模式
想要给现有的一个对象加上额外的功能,就可以用装饰者模式,新产生的装饰类是在之前的类上面叠加功能。其优点是可以不通过继承就可以给就对象增添新功能。
比如有一个对象包含有形状的属性,现在要添加颜色的功能,就可以使用装饰者模式。
image.png
外观模式
隐藏系统的复杂性,向外提供客户想要的接口和功能,和代理模式类似,就不细讲了。
享元模式
简单说就是缓存模式。享元:共享对象。此模式常用于相同的对象被反复创建,会消耗大量的内存开销,因此每次在创建内存时会先检查缓存是否有相同的对象,若有则直接从缓存里取,若没有则新建一个对象实例,并将此对象存入缓存,以备下次新建对象时复用。如String常量池、数据库连接池、缓冲池等等。通常用的最多的是使用hashMap来进行缓存。
模板方法模式
桥接模式
桥接模式通常用于较为复杂的对象关系中,主要防止多层继承,抽象出多个整体特征,利用多个接口或者接口和继承交表现对象之间的关系。例如计算机品牌有戴尔,联想,苹果等,从体型上看又分为台式机和笔记本。如果使用继承则不适合,所以使用多个抽象接口或者一个接口+一个抽象类最好。
组合模式
组合模式就是相对于继承而言,对于多个维度关系复杂的对象,优先用组合而不是继承。
下面看一个例子。
用组合模式实现当用户在商店购物后,显示其所选商品信息,并计算所选商品总价的功能。
说明:假如李先生到韶关“天街e角”生活用品店购物,用 1 个红色小袋子装了 2 包婺源特产(单价 7.9 元)、1 张婺源地图(单价 9.9 元);用 1 个白色小袋子装了 2 包韶关香藉(单价 68 元)和 3 包韶关红茶(单价 180 元);用 1 个中袋子装了前面的红色小袋子和 1 个景德镇瓷器(单价 380 元);用 1 个大袋子装了前面的中袋子、白色小袋子和 1 双李宁牌运动鞋(单价 198 元)。
最后“大袋子”中的内容有:{1 双李宁牌运动鞋(单价 198 元)、白色小袋子{2 包韶关香菇(单价 68 元)、3 包韶关红茶(单价 180 元)}、中袋子{1 个景德镇瓷器(单价 380 元)、红色小袋子{2 包婺源特产(单价 7.9 元)、1 张婺源地图(单价 9.9 元)}}},现在要求编程显示李先生放在大袋子中的所有商品信息并计算要支付的总价。
image.png
代理模式
很好理解,就是委托中间人或者助理来替自己处理一些事情的模式。为一个对象提供一种委托类,访问这个委托类已达到请求和控制这个对象的目的。
需要代理的行为被抽象为一个接口或者抽象类,代理类和被代理对象都实现了这个接口,用户只需调用代理类即可访问对被代理对象的控制。
例如,ActivityManager 作为客户端要访问 AMS,AMS 不希望直接暴露在客户端面前,或者不想被客户端的某些操作影响到自己内部结构,就暴露出一个代理对象ActivityManagerProxy,让ActivityManagerProxy参与客户端与服务端的交互,这样就完美了。
image.png
静态代理
类似上面这种,我们清楚地知道被代理对象和代理类,可以直接的实现代理行为就行了。在程序运行前,代理类的.class文件就已经创建好了。
动态代理
在程序运行时,代理类时运用反射机制动态创建而生成的。主要使用到了两个类:invocationHandle和Proxy,这两个都是invocationHandle动态生成了一个实现给定接口的对象,相当于被代理对象,我们可以在它实现接口的前后进行一些其他操作,用以增强它的功能;而Proxy则生成一个代理对象。如下图:
image.png
例:有一个接口类hello
public interface Hello {
public void say();
}
接口实现类HelloImp
public class HelloImp implements Hello{
@Override
public void say() {
System.out.println("hello ...");
}
}
万能接口功能增强实现类
public class ProxyHandle implements InvocationHandler {
private Object hello;
public ProxyHandle(Object hello) {
this.hello = hello;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before hello say ...");
method.invoke(hello,args);
System.out.println("after hello say ...");
return null;
}
}
测试
public static void main(String[] args) {
Hello hello = new HelloImp();
InvocationHandler helloHandle = new ProxyHandle(new HelloImp());
Hello proxyHello = (Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(),hello.getClass().getInterfaces(),helloHandle);
proxyHello.say();
}
网友评论