您好,欢迎访问三七文档
适配器模式(Adapter)2020/12/261结构型模式结构型模式(StructuralPattern)描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构。结构型模式分为类结构型模式和对象结构型模式:类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系。对象结构型模式关心类与对象的组合,通过关联关系使得在一个类中定义另一个类的实例对象,然后通过该对象调用其方法。结构型模式根据“合成复用原则”,在系统中尽量使用组合关系来替代继承关系,因此大部分结构型模式都是对象结构型模式。结构型模式结构型模式结构型模式简介–适配器模式(Adapter)–桥接模式(Bridge)–组合模式(Composite)–装饰模式(Decorator)–外观模式(Facade)–享元模式(Flyweight)–代理模式(Proxy)Adapter(适配器)模式“不合适的插座”你的电脑的插头是三相的而墙上的插座只有两相的插头和插座的“接口”不匹配,怎么办?Adapter(适配器)模式客户适配器请求转换后的请求接口转换面向对象软件系统的适配问题假设我们已经有一个软件系统,原来使用了一个第三方类库A。现在有一个新的第三方类库B,其功能等各方面都更加强大。我们希望用B来替换A,以改善我们的系统。但是B的接口与A不一样。那怎么办呢?办法之一BNewSystemBAdapter办法之二ASystemBAdapter第二种方案的优点System不需要修改代码不需要修改代码新代码办法之三B’SystemB示例鸭子接口publicinterfaceDuck{publicvoidquack();publicvoidfly();}鸭子接口Duck,定义鸭子具有“鸣叫”和“飞行”方法MallardDuck类publicclassMallardDuckimplementsDuck{publicvoidquack(){System.out.println(嘎嘎嘎...);}publicvoidfly(){System.out.println(我在飞哦!);}}MallardDuck类简单地实现了Duck接口。现在有一种新家伙publicinterfaceTurkey{publicvoidgobble();publicvoidfly();}WildTurkeypublicclassWildTurkeyimplementsTurkey{publicvoidgobble(){System.out.println(咕咕咕...);}publicvoidfly(){System.out.println(我在飞,不过飞不远);}}问题?我们原来有一个程序使用鸭子对象,现在想让它使用火鸡对象,但是火鸡与鸭子的接口不同,不能直接使用。写一个火鸡适配器,让火鸡看起来像鸭子火鸡适配器publicclassTurkeyAdapterimplementsDuck{Turkeyturkey;publicTurkeyAdapter(Turkeyturkey){this.turkey=turkey;}publicvoidquack(){turkey.gobble();}publicvoidfly(){for(inti=0;i5;i++){turkey.fly();}}}火鸡适配器包装了一个火鸡对象,同时实现了鸭子接口。这样就可以像使用鸭子一样使用火鸡了。使用适配器publicclassDuckTestDrive{publicstaticvoidmain(String[]args){MallardDuckduck=newMallardDuck();WildTurkeyturkey=newWildTurkey();DuckturkeyAdapter=newTurkeyAdapter(turkey);System.out.println(火鸡说...);turkey.gobble();turkey.fly();System.out.println(\n鸭子说...);testDuck(duck);System.out.println(\n火鸡适配器说...);testDuck(turkeyAdapter);}staticvoidtestDuck(Duckduck){duck.quack();duck.fly();}}需要使用鸭子对象在需要鸭子对象的地方使用了火鸡适配器对象,火鸡适配器对象包装了一个火鸡对象,所以实际使用的是火鸡对象。分析被适配者火鸡接口客户要使用鸭子对象的程序适配器把火鸡装扮成鸭子目标接口:鸭子接口两者无耦合彼此不必知道对方的存在两者无耦合彼此不必知道对方的存在试试看如果希望把鸭子包装成火鸡该怎么做?写出你的代码DuckAdapterDuckAdapterimportjava.util.Random;publicclassDuckAdapterimplementsTurkey{Duckduck;Randomrand;publicDuckAdapter(Duckduck){this.duck=duck;rand=newRandom();}publicvoidgobble(){duck.quack();}publicvoidfly(){if(rand.nextInt(5)==0){duck.fly();}}}别名:包装器(Wrapper),变压器模式概念理解适配器模式把一个类的接口(被适配者)变换成客户端所期待的另一种接口(目标),从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。该模式中涉及有目标、被适配者和适配器。适配器模式的关键是建立一个适配器,这个适配器实现了目标接口并包含有被适配者的引用。适配器模式的结构与使用适配器模式的两种形式:①类的适配器模式②对象的适配器模式类的适配器模式(ClassAdapter)结构Adapter+request()...Target+request()...Adaptee+specificRequest()...ClientspecificRequest();客户Client目标(Target)客户所期待的接口被适配者(Adaptee):一个已经存在的、需要适配的类,它具有Client要求的功能但不符合Client的接口要求适配器(Adapter)对Adaptee的接口与Target接口进行适配适配器模式的核心类被适配者Adaptee类没有Request方法,而客户期待这个方法为使客户能够使用Adaptee类,提供一个中间环节,即类Adapter类Adapter类实现Target接口,继承Adaptee,Adapter的Request方法重新封装Adaptee的SpecificRequest方法,实现适配的目的//目标publicinterfaceITarget{voidRequest();}//被适配者publicclassAdaptee{publicvoidSpecificRequest(){System.out.println(calledSpecificRequest());}}//适配器publicclassAdapterextendsAdapteeimplementsITarget{publicvoidRequest(){this.SpecificRequest();}}publicclassTest{publicstaticvoidmain(String[]args){ITargett=newAdapter();t.Request();}}类适配器效果①用Adapter类对Adaptee和Target进行匹配。当想要匹配一个类以及所有它的子类时,类Adapter将不能胜任工作②使得Adapter可以重定义Adaptee的部分行为,因为Adapter是Adaptee的一个子类。③仅仅引入一个对象,并不需要额外的指针以间接得到adaptee对象适配器模式(ObjectAdapter)结构adapteeAdapter+request()...Adaptee+specificRequest()...Clientadaptee.specificRequest();Target+request()...客户端需要调用Request方法,而Adaptee没有该方法,为了使客户端能够使用Adaptee类,需要提供类AdapterAdapter包装一个Adaptee的实例,从而将客户端与Adaptee衔接起来由于Adapter与Adaptee是委派关系,这决定了这个适配器模式是对象的//目标publicinterfaceITarget{//MethodsvoidRequest();}//被适配者publicclassAdaptee{publicvoidSpecificRequest()//Methods{System.out.println(CalledSpecificRequest());}}//适配器publicclassAdapterextendsAdapteeimplementsITarget{Adapteeadaptee=newAdaptee();publicvoidRequest(){adaptee.SpecificRequest();}}publicclassClient{publicstaticvoidmain(String[]args){ITargett=newAdapter();t.Request();}}①允许一个Adapter与多个Adaptee及它们所有子类同时工作。Adapter也可以一次给所有的Adaptee添加功能②使得重定义Adaptee的行为比较困难。这就需要生成Adaptee的子类并且使得Adapter引用这个子类而不是引用Adaptee本身。对象适配器效果将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。适配器模式的优缺点适配器模式的优缺点类适配器模式优点:由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。类适配器模式缺点:对于不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。对象适配器模式优点:一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。对象适配器模式缺点:与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。适配器模式的优缺点在什么情况下使用适配器模式系统需要使用现有的类,而此类的接口不符合系统的需要。想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。这些源类不一定有很复杂接口(对对象适配器而言)在设计里,需要改变多个已有子类接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器,而这不太实际。有一个类(adaptee)实现了数学中的幂次运算,方法中需要传入两个参数,一个是基数base,另外一个是幂次exp。现在客户端需要一个求得一个数的平方的函数接口(target),传入一个数,得到它的平方值。为了复用已经存在的类adaptee,适用Adapter来适配adaptee,adapter实现了
本文标题:适配器模式
链接地址:https://www.777doc.com/doc-7330131 .html