设计模式之适配器模式和外观模式

工厂也来了

小明公司的项目越来越多,一家做污水处理的工厂也找上门了,这家污水处理厂最近和一家新的工厂签约了,这家新签约排放污水的工厂之前是和另一个污水处理厂合作,但是之前那家倒闭了,找到了他们,但是他们遇到了一个问题,排放污水的工厂不想改变他们之前排放污水的方式,但是现在这家污水处理厂接收污水的方式又和之前的污水处理厂的接收污水的方式完全不同,所以找到小明他们公司,希望能帮助解决。

这是排放污水工厂之前的方式,排放类:

public interface Discharge{
    public void oldDischargeSewage();
}

排放实现类:

public class OldFactoryDischarge implements Discharge{

    // 省略其他细节

    public void oldDischargeSewage(){
        // 具体的实现
    }
}

污水排放工厂:

public class SewageFactory{
    // 用排放类排放
    pubclic void discharge(Discharge discharge){
        discharge.oldDischargeSewage();
    }
}

排放:

Discharge discharge = new OldFactoryDischarge();

// 工厂不想变动使用排放的方式
SewageFactory sewageFactory = new SewageFactory();
sewageFactory.discharge(discharge);

而新的污水处理厂接收污水并处理的是这样的:

public class NewFactoryDischarge {

    // 省略其他细节

    public void newDischargeSewage(){
        // 接收污水的实现
    }
}

小明和主管一起开会讨论,主管说是该适配器登场的时候了。小的主管只让小明新加了一个类:

public class FactoryDischargeAdapter implements Discharge{

    NewFactoryDischarge newFactoryDischarge;

    public NewFactoryDischarge(NewFactoryDischarge newFactoryDischarge){
        this.newFactoryDischarge = newFactoryDischarge;
    }

    public void oldDischargeSewage(){
        newFactoryDischarge.newDischargeSewage();
    }
}

然后新的排放方式就成这样了:

Discharge discharge = new FactoryDischargeAdapter(new NewFactoryDischarge());

// 工厂不想变动使用排放的方式和之前没有任何变化
SewageFactory sewageFactory = new SewageFactory();
sewageFactory.discharge(discharge);

小明很快就清楚了这就是适配器模式,接口使用者,在这里也就是污水排放的工厂不想改变旧的排放方式,但接收方又和之前的方式不一样,这样就引进了适配器类,它的作用就是完全的避免使用接口的客户端和实现接口的另一端的耦合。小明的主管又说了,小明,刚才我们使用的这种方式,严格的说它应该叫对象适配器模式,还有另外一种适配器模式,它叫类适配器,你知道该怎么做吗?小明思考了一会,从名字领悟到了这两种方式的区别,然后很快的实现了它:

public class FactoryDischargeAdapter extends NewFactoryDischarge implements Discharge{

    public void newDischargeSewage(){
        // 接收污水的实现
    }

    public void oldDischargeSewage(){
        newDischargeSewage();
    }
}

排放污水:

Discharge discharge = new FactoryDischargeAdapter();

// 工厂不想变动使用排放的方式和之前没有任何变化
SewageFactory sewageFactory = new SewageFactory();
sewageFactory.discharge(discharge);

的确,从名字就可以读出,对象适配器是通过适配器和新的需要适配的类组合实现适配,而类的方式没有组合,通过直接继承需要适配的类实现适配,两者用法不同,但是都达到了同样的效果。两种应该在不同的场景下被选择,比如对象的适配器比较适配那些变化不大的,不会有更新扩展的的类,因为一旦对象变化了,需要修改适配器本身去适应新的变化。而类的适配器更适合适配单一的需要适配的类,因为如果适配器中牵扯到多个类时,类的适配方式就不那么灵活了,所以我们应该因材施教。

适配器定义

将一个类的接口,装换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

对象适配器:

对象适配器

类适配器:

类适配器

说一说适配器模式和装饰者模式

回想一下装饰者模式,好像和适配器非常相似,那么两者有什么区别呢?其实他们的区别从定义就可以总结出来:装饰者会对装饰的组件增加新的责任,也就是功能,但是适配器没有给适配对象增加的责任,而只是让它满足客户的需求,好比有一个中间人,联络着客户和适配方。

标题中的另一种模式

文章的标题还提到了另一种模式:外观模式,为什么这次是两个模式一起来讲呢?因为外观模式和适配器模式非常相似,甚至有人任务两种模式是同一种模式,其实不然,外观模式和适配器模式用法是不一样的,也就是他们有各自的用途,我们已经知道适配器模式的用途,那么接下来看看外观模式的用途。

极客小明

小明是一名极客,特别喜欢把各种东西攒在一起,这不,他为了给家里营造更好的观影感受,买了一大堆电子产品,有投影仪、自动屏幕、音响、DVD,甚至还有一个爆米花机。但是每次观影时的他是这样的:

  • 打开投影仪
  • 接通自动屏幕
  • 打开调试音响音量
  • 打开DVD放入碟片
  • 将玉米放入爆米花机……

实在太繁琐了!小明不想做这一切,如果他只需要按一下遥控器,其他的这些动作都不用他去一个一个完成该多好,这时候,外观模式就派上用场了!外观模式是干什么的呢,他就是向外部提供一个接口,然后内部去完成一些复杂的、多步骤的、使用其他很多对象动作的功能。而对于外观的使用者来说,只需要调用一个动作即可,这就是外观模式。所以,小明去国外买了一个机器人,然后让机器人学会了他之前做的上述一切事情,每次小明回家就只对机器人说:我要看电影!然后只需要美美的坐在沙发上稍加等待,就可以开始观看优美的电影了。

以前的小明:

openProjector();
openSceen();
openSound();
openDVD();
……
// 观影结束后还要关闭它们(省略)……

现在的小明:

Robot robot = new Robot();    
robot.open();
// 观影结束
robot.off();

我们看到,对于小明来说,之前需要做很多事,现在只需要做很简单的动作就可以了,这就是外观模式给使用者带来的好处。

外观模式的定义

提供一个统一的接口,用来访问子系统中的一群接口。外观模式定义了一个高层接口,让子系统更容易使用。

外观模式完美体现了最少知道原则

外观模式

那么通过对外观模式和适配器模式的深入了解,我们也能很清楚的知道他们之间的不同点了:外观模式是为了让接口更简单,而适配器是为了适配客户的接口。

坚持原创分享,您的支持将鼓励我不断前行!