设计模式之Adapter模式

    xiaoxiao2021-03-25  114

           今天这篇文章,我们来讲将设计模式中的“Adapter模式”,中文就是“适配器模式”。先说说一个生活中适配器模式的案例,有助于理解。现在有一个100伏特的交流电源,我现在想给笔记本充电,但是笔记本只能用12伏特的直流电,那我们是不是不能用这个电源进行充电了?直接充肯定不行,但是我们可以有一个充电器,这个充电器的功能是将100伏特的交流电转化成12伏特的直流电给电脑用。请注意,这句话很重要:“电脑并不知道充电器内部做了些什么,他只知道,可以用”。

           现在运用到编码中来其主要特征就是:已经存在稳定功能的类的时候,新的需求需要去用这个类中所有或者部分功能,或者除此类的功能之外还得加新的功能,那Adapter模式就派上用场了。我们先看代码,然后再来说说细节:

           现在我已经存在一个稳定的类Banner,并且已经测试稳定了,这个类不会再改动。这个类中有两个方法,showWithParen打印出一句话用括弧包起来,还有一个showWithAster打印一句话用星号"*"包起来。现在我有一个需求需要用到这两个方法,需要我去设计一个框架结构来完美的实现。

            传统的编程来说很简单,直接new一个Banner对象,调用这里面的方法就行了。如果我需要更多的功能,那就增加一个类,在新的类中增加别的功能就行了。这种方式那就是面向实现编程了,类和类之间出现强耦合问题,一个类需要修改,相关的类都得改。如果代码出现问题,我们去维护的时候,就需要更改很多个类,并且还不好追踪问题所在。这就不好了,所以才会有了我们的设计模式登场嘛!我们理论的话不多说,往下看!

    /** * 本案例中,该类是一个早就已经功能稳定的类,现 * 在在新的版本或者需求中要用到这里面的方法 * Created by PICO-USER on 2017/3/9. */ public class Banner { private String string; public Banner(String string) { this.string = string; } public void showWithParen() { System.out.print("( " + string + " )\n"); } public void showWithAster() { System.out.print("* " + string + " *\n"); } }

    现在这个稳定的Banner类已经存在了,现在我需要定义一个接口Print,这个接口中有两个方法showWeak和showStrong,这两个方法只是表明了行为,显示两句话。具体是怎么实现,得看实现它的类,怎么去实现了。

    /** * Created by PICO-USER on 2017/3/9. */ public interface Print { public abstract void showWeak(); public abstract void showStrong(); } 接着我定义一个类PointBanner,继承了Banner,并且实现了Print接口,很简单,调用了父类的构造方法,和showWithParen方法和showWithAster方法。

    /** * Created by PICO-USER on 2017/3/9. */ public class PrintBanner extends Banner implements Print { public PrintBanner(String string) { super(string); } @Override public void showWeak() { showWithParen(); } @Override public void showStrong() { showWithAster(); } } 现在来看AdapterRun类的调用代码,和实现功能。

    public class AdapterRun { public static void main(String[] args0) { Print print = new PrintBanner("Hello World !"); print.showWeak(); print.showStrong(); } } 最后的输出结果很简单:

    ( Hello World ! ) * Hello World ! *

    在上面做了这么多事儿,最后就输出了两句话,有网友估计会说,无缘无故的你增加一个Print接口,你这不是更麻烦了吗?其实不然,代码上是多了一些,但是这就将面向实现编程转换成了面向接口编程。面向接口编程,代码量肯定会增加,但是代码的可读性,维护性,灵活性,可拓展性毫无疑问是大大增强的。具体的我们继续往下看。

           细心的网友应该能发现,在AdapterRun类中,我们使用了Print类型来保存了PrintBanner类型的实例。为什么这样做呢?一般的写法是这样的PrintBanner print = new PrintBanner("Hello World !"),我们暂且成这种方式为方式2,示例代码中的方式我们称为方式1。方式1中是完全是使用Print接口调用showWeak方法和showStrong方法,因为是用print去调用的方法,那么你是不能调用showWithParena方法和showWithAster方法的。因为Print跟Banner是两个完全不相干的东西。如果不是按照方式1而是按照方式2,那就是用PrintBanner类去调用方法,这性质就完全变了,因为PrintBanner继承了Banner类,所以这种方式是可以直接调用showWithParen方法和showWithAster方法的。最重要的问题是:我们按着Ctrl点击该方法,方式1跳转到的是Print接口,方式2是跳转的PrintBanner类。问题这就出来了,方式1的使用和接口Print的使用完全将PrintBanner类和Banner类中的方法隐藏起来了,没有暴露出来。AdapterRun类完全不知道PrintBanner类和Banner中方法的实现,他也不需要关心,只需要用就行,这就弱化了PrintBanner类和AdapterRun类的耦合性,当需求更改的时候,我们可以在完全不需要更改AdapterRun类的情况下修改PrintBanner类来实现我们的新需求

         上面是实现接口的方式实现Adapter模式,其实我们也可以用委托的方式来实现Adapter模式。委托就是把这个功能让某人代替去执行,直接看代码:AdapterRun类和Banner类不需要动,只需要把Print接口改成类,然后稍微修改PrintBanner类即可。

    /** * Created by PICO-USER on 2017/3/9. */ public abstract class Print { public abstract void showWeak(); public abstract void showStrong(); }

    /** * Created by PICO-USER on 2017/3/9. */ public class PrintBanner extends Print { private Banner banner; public PrintBanner(String string) { this.banner = new Banner(string); } @Override public void showWeak() { banner.showWithParen(); } @Override public void showStrong() { banner.showWithAster(); }

    思想都是一样的,面向接口编程和面向抽象类编程其实都是面向抽象编程,都一样的。

    转载请注明原文地址: https://ju.6miu.com/read-9830.html

    最新回复(0)