适配器模式和装饰模式都是经过组合类或者对象产生更大结构以适应更高层次的逻辑需求。其中装饰模式是代理模式的一个特殊应用,侧重于对类的功能进行增强和减弱。适配器模式则是侧重于将源角色转换的过程。设计模式
结构型设计模式关注重点在于多个对象间的组合,而建立型设计模式关注重点在于一个对象内部结构。markdown
适配器模式关键点在于转换,将源角色转换成目标角色。ide
具体定义以下:函数
将一个类的接口变换成客户端所期待的另外一种接口,从而使本来因接口不匹配而没法在一块儿工做的两个类可以在一块儿工做。ui
有三个关键角色this
目标类,适配器类即将要适配的抽象类或者接口,就是须要把其余类转换成什么接口spa
适配器类,你想把谁转换成目标角色,通过适配器包装,就是一个全新的角色设计
具体适配器类,能够实内部的类,也能够是外部的类代理
具体看代码,会很容易理解code
//源角色
public class Adaptee{
public void adapteeEat(){
System.out.println("饭太贵,吃不起");
}
}
//目标角色
public interface Target{
public void targetBuyThings();
}
//目标角色的实现类
public class ConcreteTarget implements Target{
@Override
public void targetBugThings(){
System.out.println("东西太贵,买不起");
}
}
//适配器角色
public class Adapter extends Adaptee implements Target{
@Override
public void targetBugThings(){
super.adapteeEat();
System.out.println("东西太贵,买不起");
}
}
//场景类
public class Client{
public static void main(String[] args){
Target target = new Adapter();
target.targetBuyThings();
}
}
复制代码
代码很简单,利用了接口,达成了多继承目的,实现了不一样类之间的关联,能够理解为中间者将两个类封装到了一块儿。
那若是咱们的Adaptee
信息来自不一样的类呢?如何处理,以下在构造函数中处理或者 get
、set
方法处理
public class Adapter implements Target{
private Adaptee adaptee1;
private Adaptee adaptee2;
public Adapter(Adaptee adaptee1,Adaptee adaptee2){
this.adaptee1 = adaptee1;
this.adaptee2 = adaptee2;
}
@Override
public void targetBugThings(){
super.adapteeEat();
System.out.println("东西太贵,买不起");
}
}
复制代码
这里可能你们还听过对象适配器和类适配器,这两种类型适配器,有什么不一样?
类适配器是类间继承
对象适配器是对象的合成关系
场景比较多,可是只须要记住,你须要修改一个已经投产中的接口时,适配器模式多是最适合的模式,例如系统扩展了,须要使用一个已经有的或者新创建的类,这是能够考虑适配器模式。或者是不一样数据格式、协议须要转换的时候,好比,API 网关中常常须要对 iOS、安卓、H5 等不一样的客户端进行数据和通讯协议上的适配转换,这时网关就是一个是适配器。
适配器模式通常是用于解决服役项目问题,最好不要在详细阶段考虑它,毕竟主要场景仍是在扩展应用方面。
让两个没有任务关系的类在一块儿运行
增长了类的透明型,具体的适配者类中新增功能只影响适配者类,而对于使用目标类的客户端类来讲是透明的(使用目标类接口)
提升了类的复用度
符合开闭原则
知足里氏替换原则
一次只能适配一个抽象类或者接口
过分嵌套会致使接口臃肿
目标接口依赖太多适配接口,修改目标接口会致使全部适配接口都得改,太多Adapter
依赖 Target
, Target
修改了方法,全部Adapter
都须要改。对应以前提到的 Adaptee
不少的状况
动态地给一个对象添加一些额外地职责
//抽象构件
public abstract class Component{
//抽象方法
public abstract void operate();
}
//具体构件
public class ConcreteComponent extends Component{
@Override
public void operate(){
System.out.println("operate car");
}
}
//抽象装饰者
public abstract class Decorator extends Component{
private Component component = null;
public Decorator(Component component){
this.component = component;
}
//委托给被修饰者执行
@Override
public void operate(){
this.component.operate();
}
}
//具体装饰类
public class ConcreteDecorator1 extends Decorator{
//定义被修饰者
puiblic ConcreteDecorator1(Component component){
super(component);
}
//定义本身的修饰方法
private void method1(){
System.out.println("method1修饰");
}
//重写父类
public void operate(){
this.method1();
super.operate();
}
}
复制代码
最简单的理解就是,用一个类持有另外一个类,新类里方法调用能够操做另外一个类的方法,这里的方法要留意一下,都是operate
方法,这种模式其实也能够说是继承关系的一个替代方案
原始方法和装饰方法的执行顺序在具体的装饰类是固定的,能够经过方法重载实现多种执行顺序
须要动态扩展一个类的功能,或者给一个类增长附加功能
须要为一批兄弟类进行改装
经过顺序组合包装的方式来附加扩张功能的场景
例如数据上报,埋点,新功能须要更加详细,能够考虑下装饰者模式
装饰类和被装饰类能够独立发展,不会相互耦合(看上面的具体代码,这两个类都实现了基础类接口)
动态扩展功能
能够在统一行为上组合几种行为
知足单一职责原则
在调用链中删除某个装饰器时须要修改代码,为何?看下面代码
Component component = new ConcreteComponent();
//第一次修饰
component = new ConcreteDecorator1(component);
//第二次修饰
component = new ConcreteDecorator2(component);
//修饰后运行
component.operate();
复制代码
若是修饰类嵌套过多,会增长代码的理解难度,后续维护和排查问题的难度
适配器模式和装饰者模式都属于结构型模式,功能都相似,都是包装做用。
装饰模式强调的是 动态扩展功能,全部装饰类都有一个共同的父类,而适配器模式侧重于转换,经过继承和实现方式,将源角色转换成目标角色,