代理模式
代理模式就是给某一个对象创建一个代理对象,由这个代理对象控制对原对象的引用,而创建代理对象后可以在调用原对象是增加一些额外的操作。
代理模式的结构:
- Subject:抽象主题,被代理类以及代理类都要实现的接口,可以由多个接口组成;
- ProxySubject:代理类,除了实现抽象主题定义的接口外,还必须持有被代理类的引用;
- RealSubject:被代理类,就是目标对象。
策略模式
策略模式,就是在做某件事时的策略,就是说在完成某一个操作的时候可能有很多种方法,但是对于不同的环境不同的条件,各个方法都有派上用场的时候。把各个操作的方法都当做一个可以实现的策略,用户可以根据需求采用合适的策略。
策略模式的结构:
- Contex:使用不同的策略,它可以根据不同自身的条件选择不同的策略实现类来完成所要的操作。它持有一个策略实例的引用。创建具体策略对象的方法也可以由它完成;
- Strategy:抽象策略,定义每一个具体策略类都要实现的策略方法;
- ConcreteStrategy:具体策略实现类,实现在抽象策略中定义的方法。
Spring 中策略模式的实现
Spring AOP的代理方式有JDK动态代理和CGLib代理。对这两种代理方式的选择使用就是使用了策略模式,结构图如下:
抽象策略:AopProxy接口;
具体策略实现类:Cglib2AopProxy和JdkDynamicAopProxy实现类;
Context:使用场景—ProxyFactoryBean,它根据条件选择使用JDK代理方式还是CGLib方式。
另外三个类主要负责创建具体的策略对象,ProxyFactoryBean通过依赖的方法来关联具体策略实现类的,通过调用抽象策略AopProxy的Object getProxy(ClassLoader classLoader);方法来完成操作。
模板模式
模板模式在框架设计时使用较多,因为框架的作用就是给开发者创建了一个方便的模板,开发者只需要实现模板的一些接口就能实现一个很复杂的功能,很多操作已经在模板里面设计好了。
模板的核心概念就是,大体的逻辑已经定义好了,开发者要做的就是实现一些具体的步骤,然后不同的开发者使用这个模板时实现的具体步骤的方法会有所不同,从而不同的人使用模板构建的行为能够表现出不同的行为。
由抽象父类定义主体执行流程,由子类去实现流程中的单个步骤。
模板模式的结构:
- Abstract(抽象模板):定义了完整的框架后,方法的调用顺序基本确定,但是会留有一些抽象方法给子类去实现。
- Concrete(具体模板实现类):实现抽象模板中定义的抽象方法,实现具体的功能,组成一个完整的逻辑;不同的实现类可以在抽象方法中实现不一样的方法,形成不一样的逻辑。
Spring MVC中的模板模式实现
在HandlerMapping设计中,HandlerMapping有一个抽象类AbstractHandlerMapping,在抽象类中定义了一个完整的HandlerMapping的初始化和获取Handler对象的主体流程,但是有一个抽象方法protected abstract Object getHandlerInternal(HttpServletRequest request)
留给子类去实现,只要子类实现了这个方法,那么整个getHandler的流程就真正完成了。
在View设计中一样使用了模板模式,view的结构图如下:
View只是定义了接口方法,AbstractView类实现了在View中定义的所有方法,并留有一个抽象方法renderMergedOutputModel给子类去实现。而AbstractJasperReportsView和AbstractTemplateView抽象类进一步实现类AbstractView的抽象方法,并进一步分别细化出renderReport抽象方法和renderMergedTemplateModel抽象方法给子类去进一步实现。结构上,越是往下的子类需要实现的功能就越少,模板模式能加快整个程序的开放进度。
适配器模式
适配器模式,就是将一个类接口变换成客户所能接受的另外一种接口,从而使两个不匹配而无法在一起工作的两个类能够在一起工作,从而实现客户所需的两种功能需求。
适配器模式结构图如下:
- Target(目标接口):所要转换的期待的接口,客户想要的接口;
- Adaptee(源接口):需要适配的接口;
- Adapter(适配器):将源接口适配成目标接口,需要继承源接口,并持有目标接口引用。
例如Java的I/O库中,客户需要从流中读文件(Inputstream),并且需要以字符串形式读(Reader),这是两种不一样的接口,不一样的功能实现,要实现两种功能一起实现,需要适配器将两种接口适配。
- Target(目标接口):Reader
- Adaptee(源接口):InputStreamReader
- Adapter(适配器):InputStream
InputStreamReader实现Reader接口,并通过StreamDecoder间接持有了InputStream的引用,因此InputStreamReader将InputStream适配到了Reader,用户调用Reader时就能够在流中以字符的形式读取数据。
装饰器模式
装饰器模式的目的就是要为某一个类重新装扮一下,使得这个类更加漂亮了,也就是功能更强了。作为被装饰类的使用者还不能感受到装饰前后的区别,因此装饰器模式要做到对被装饰类的使用者透明。
装饰器模式结构图:
Component:抽象组件角色,定义一组抽象的接口,规定这个装饰组件都有哪些功能。也就是被装饰类。
ConcreteComponent:实现抽象组件的所有功能,也就是被装饰类没有被装饰的情况下应该具备的功能。
Decorator:装饰器角色,持有一个Component对象实例的引用,并要实现Component所有功能,在实现了抽象组件所有功能之后,还可以自己定义一些方法,用来增强修饰Component。
ConcreteDecorator:具体的装饰器实现者,继承Decorator,负责实现装饰器角色定义的功能,完成装饰功能,对抽象组件进行增强。
在IO库中的FilterInputStream就是一个装饰器,它的类结构图如下:
Component:InputStream,这个类定义了基本的输入流操作。
ConcreteComponent:FileInputStream,实现InputStream的所有功能,可以完成完整的输入流功能。
Decorator:filterInputStream就是装饰器角色,持有一个InputStream对象实例的引用,并实现了InputStream所有功能。
ConcreteDecorator:BufferedInputStream,具体的装饰器实现者,继承Decorator,给InputStream类附加了功能,使得InputStream读取的数据保存在内存中,提高读取的性能。
适配器模式与装饰器模式的区别
从以上的描述,咋一看两个模式的作用都对一个类进行了包装作用,但是两种模式设计的目的是不一样的,适配器模式的目的是为了将一个接口转变成另外一个接口,它通过改变了接口达到重复使用的目的;而装饰器模式并非要改变一个接口,而是要保持原有接口的功能,在原有接口的功能基础上,增强原有接口,从而改变原有接口的处理方法达到提高性能的目的。