精华内容
下载资源
问答
  • 2021-11-10 15:20:31

    适配器模式

    定义

    适配器模式(Adapter Pattern)将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。 ——《HEAD First设计模式》

    适配器模式分为类结构型模式对象结构型模式两种。

    主要角色

    目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。客户想使用的那个类或接口。可以理解为出国旅行使用的那个充电子插头。
    适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。是实际上工作的那个类。可以理解为出国旅行,酒店提供的那个实际上的插口。
    适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。可以理解为出国旅行携带的电源转换器。
    下图是对象适配器模式:
    在这里插入图片描述

    下图是类适配器模式:
    在这里插入图片描述

    对象适配器模式

    例子来源于《HEAD First设计模式》,实现火鸡和鸭子的适配器。
    客户想使用鸭子对象,拿一些火鸡来冒充鸭子,需要实现一个鸭子到火鸡的适配器。鸭子对象和第一篇[设计模式1 策略模式]是一致的(https://blog.csdn.net/mxb1234567/article/details/120677314)
    首先是鸭子接口:

    public interface Duck{
    	public void quack();
    	public void fly();
    }
    

    具体的鸭子类:

    public MallardDuck implements Duck{
    	public void quack()
    	{System.out.println("Quack");}
    	public void fly()
    	{System.out.println("I'm flying");};
    }
    

    然后是火鸡类:

    public interface Turkey{
    	public void gobble();
    	public void fly();
    }
    

    火鸡飞行是一次飞行一小段距离:

    public class WildTurkey implements Turkey{
    	public void gobble()
    	{System.out.println("Gobble");}
    	public void fly()
    	{System.out.println("Fly short distance");}
    }
    

    那么,适配器就可以是:

    public class TurkeyAdapter implements Duck{
    	Turkey turkey;
    	public TurkeyAdapter(Turkey turkey)
    	{
    		this.turkey = turkey;
    	}
    	public void quack()
    	{
    		turkey.gobble();
    	}
    	public void fly()
    	{
    		for(int i = 0;i < 5;i++)
    			turkey.fly();
    	}
    } 
    

    这样在使用火鸡伪装的鸭子时,可以这样:

    public class Test
    {
    	public static void main(String[] args)
    	{
    		WildTurkey turkey = new WildTurkey();
    		Duck turkeyAdapter = new TurkeyAdapter(turkey);
    		testDuck(turkeyAdapter);
    	}
    	static void testDuck(Duck duck)
    	{
    		duck.quack();
    		duck.fly();
    	}
    }
    

    因此可以看出,客户通过目标接口(Duck),调用适配器(TurkeyAdapter)的方法(quack()、fly())对适配器发出请求,适配器把请求转换为被适配者(Turkey)的一个或多个调用接口。这个过程中对用户是透明的,用户是不知道适配器在起作用的。
    这种适配器不光可以适配某个类,还可以适配任何这个类的子类。

    类适配器

    类适配器模式可采用多重继承方式实现。Java中不允许多重继承,可以继承Target接口和Adaptee类,来实现类适配器。
    Target接口,即目标接口(Duck):

    public interface Duck{
    	public void quack();
    	public void fly();
    }
    

    再来实现一个Adaptee,即上个例子中的Turkey:

    public interface Turkey{
    	public void gobble();
    	public void fly();
    }
    
    public class WildTurkey implements Turkey{
    	public void gobble()
    	{System.out.println("Gobble");}
    	public void fly()
    	{System.out.println("Fly short distance");}
    }
    

    实现一个类的适配器TurkeyAdapter可以这样:

    public class TurkeyAdapter extends WildTurkey implements Duck{
    	public TurkeyAdapter(){}
    	public void quack()
    	{
    		super.gobble();
    	}
    	public void fly()
    	{
    		for(int i = 0;i < 5;i++)
    			super.fly();
    	}
    } 
    

    类的适配器和对象适配器对比

    可以看出,对象适配器是持有Adaptee对象的,是组合关系,是动态的方式;类的适配器是继承adaptee,并且实现target方法,是静态的方式。

    这样做可以使得对象适配器可以重定义实现行为,可以override掉父类的功能函数;但是对象适配器重定义适配的行为比较困难,但是添加行为较方便。

    优缺点

    优点

    1. 可以让任何两个没有关联的类一起运行。
    2. 提高了类的复用。 不需要修改原有代码而重用现有的适配者类。
    3. 增加了类的透明度。 客户端通过适配器可以透明地调用目标接口。
    4. 在很多业务场景中符合开闭原则。

    缺点

    增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱。例如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现。

    已有使用场景

    • JAVA 中的 jdbc
    • AVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口

    适配器模式和装饰者模式对比

    装饰者模式和适配器模式都是起到包装一个类的作用,都有一个别名叫做包装模式(Wrapper Pattern)。但是使用它们的目的很不一一样。
    适配器模式的是要将一个接口转变成另一个接口,它的目的是通过改变接口调用方式来达到重复使用的目的。
    装饰器模式是不改变原有的接口,但是增强原有对象的功能,当涉及到装饰者就意味着新的行为或责任被加入了设计中。

    外观模式

    定义

    外观模式(Facade Pattern)提供了一个统一的接口,用来访问子系统中的一群接口。外观模式定义了一个高层接口,让子系统更容易使用。 ——《HEAD First设计模式》

    主要角色

    • 外观(Facade)角色:为多个子系统对外提供一个共同的接口。
    • 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。
    • 客户(Client)角色:通过一个外观角色访问各个子系统的功能。
      在这里插入图片描述
      图源:外观模式(Facade模式)详解
      简单来说,可以理解为外观模式可以实现把很多接口进行打包,用户点一下玩一年,一个接口调用其他接口干很多事情。外观模式的特点主要是简化接口,以及减少客户端对外观组件的耦合。

    例子

    例子来源于《HEAD First设计模式》,实现家庭影院的外观模式。
    家庭影院中,有个爆米花机,CD播放器,屏幕,用户使用家庭影院需要一个个的去打开关闭。这时候采用外观模式,一个函数让用户点一下玩一年。
    首先是爆米花机:

    class PopcornPopper{
        public void on(){
            System.out.println("正在打开爆米花机。。");
        }
        public void off(){
            System.out.println("正在关闭爆米花机。。");
        }
        public  void pop(){
            System.out.println("正在蹦爆米花。。");
        }
    }
    

    然后是屏幕:

    class Screen{
        public void up(){
            System.out.println("正在生起屏幕。。");
        }
        public void down(){
            System.out.println("正在放下屏幕。。");
        }
    }
    

    然后是CD播放器:

    class CDPlayer{
        public void on(){
            System.out.println("正在打开CD");
        }
        public void off(){
            System.out.println("正在关闭CD");
        }
        public void eject(){
            System.out.println("弹出CD播放器!");
        }
        public void pause(){    
        }
        public void play(){
        }
        public String toString(){
            return "hello panda";
        }
    }
    

    外观模式类:

    class HomeTheaterFacade{
        CDPlayer cd;
        Screen screen;
        PopcornPopper pop;
        //构造的时候拿到这些对象
        public HomeTheaterFacade(CDPlayer cd ,Screen screen,PopcornPopper pop){
            this.cd = cd;
            this.screen = screen;
            this.pop = pop;
        }
        //看电影  放一个方法里来执行一系列动作
        public void watchMovie(String movie){
            System.out.println("get ready to watch a movie..");
            pop.on();//首先打开爆米花机
            pop.pop();//然后蹦爆米花
            screen.down();//投影仪放下来
            cd.on();
            cd.play();
        }
        //电影结束
        public void endMovie(String movie){
            System.out.println("shutting movie theater down..");
            pop.off();
            screen.up();
            cd.off();
        }
    }
    

    对于客户而言,只需要watchMovie和endMovie:

    public class FacadePattern {
        public static void main(String args[]){
            CDPlayer cd = new CDPlayer();
            Screen screen = new Screen();
            PopcornPopper pop = new PopcornPopper();                  
            HomeTheaterFacade facade = new HomeTheaterFacade(cd,screen,pop);
            facade.watchMovie("movie");
            facade.endMovie("movie");
        }
     
    }
    

    最少知识原则

    每个类对象都要执行一些方法,如果直接new这些类创建对象去调方法会与这些类产生耦合。单独再写一个外观类,构造初始化时拿到这些类对象,在一个方法里去调这些类对象的方法,这样对客户来说只和一个类打交道,与子系统的一堆类解耦了。这个原则被称为:最少知识原则(Least Knowledge)
    最少知识原则的指导思想:
    就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:

    1. 该对象本身
    2. 被当做方法的参数而传过来的对象
    3. 该方法所创建或实例化的任何对象
    4. 对象的任何组件

    如果调用从另一个调用中返回的内容,即如下所示想另外一个对象的子部分发送请求,需要增加我们知道的对象。

    //不采用这个原则
    public float getTemp()
    {
    	Thermometer t = station.getThermometer();
    	return t.getTemperture();
    }
    
    //采用这个原则
    public float getTemp()
    {
    	return station.getTemperture();
    }
    

    这样可以减少我们所依赖的类的数目,在station里面加一个getTemperture方法。
    这个法则也被称为德墨忒尔法则(Law of Demeter)。这个原则虽然减少了对象间的依赖减少维护成本,但是采用这个原则也会导致更多包装类被制造,处理和其他组件的沟通成本上升,效率降低。

    参考

    外观模式(Facade模式)详解.
    Carson带你学设计模式:适配器模式(Adapter Pattern)
    适配器模式
    适配器模式(Adapter模式)详解
    学习编程|Head First设计模式:外观模式

    更多相关内容
  • 1.适配器模式引入 1.1 现实世界的适配器 真实世界的适配器。比如,如果需要在欧洲国家使用美国制造的笔记本电脑,那就可能需要一个交流电的适配器。 上图中适配器的作用:位于美式插头和欧式插座的中间,他的...

    1.适配器模式引入

    1.1 现实世界的适配器

    真实世界的适配器。比如,如果需要在欧洲国家使用美国制造的笔记本电脑,那就可能需要一个交流电的适配器。

    上图中适配器的作用:位于美式插头和欧式插座的中间,他的工作是将欧式插座转换成美式插座,好让美式插头可以插进这个插座得到电力。或者也可以这么认为:适配器改变了插座的接口,以符合美式笔记本电脑的需求。

    有些交流适配器相当简单,只是改变插座的形状来匹配你的插头,直接传送电流。而有些复杂的,是改变电流符合装置的需求。

    1.2 面向对象适配器

    假设已有一个软件系统,希望它能和一个新的厂商类库搭配使用,但是这个新厂商所设计的接口,与旧厂商的接口不同。

    如果不想改变现有的代码,解决这个问题的话,应该写一个类,将新厂商接口转结成所期望的接口。

     适配器工作起来就如同一个中间人,将客户所发出的请求转换为厂商类能理解的请求。

    1.3 小举例--火鸡转换器

    一只走路像鸭子,叫起来像鸭子的就一定是鸭子吗?

    也可能是一只包装了鸭子适配器的火鸡。

    以这个例子为例,看看鸭子接口和类的一个稍微简化版本:

    鸭子实现了Duck接口,具备了呱呱叫和飞行的能力。

    public interface Duck {
        
        public void  quack();
        public void  fly();
    }

    绿头鸭是鸭子的子类

    public class MallardDuck implements Duck {
    	@Override
    	public void quack() {
    		System.out.println("Quack");
    	}
     
    	@Override
    	public void fly() {
    		System.out.println("I'm flying");
    	}
    }

    然后开始建立“街头顽禽”:

    火鸡不会呱呱叫,只会咯咯(gobble)的叫,火鸡会飞,虽然飞不远

    public interface Turkey {
    	public void gobble();
    	public void fly();
    }

    火鸡的具体实现:

    public class WildTurkey implements Turkey {
    	@Override
    	public void gobble() {
    		System.out.println("Gobble gobble");
    	}
     
    	@Override
    	public void fly() {
    		System.out.println("I'm flying a short distance");
    	}
    }

    现在,假设缺少鸭子对象,想用一些火鸡对象来冒充。因为火鸡的接口不同,因此我们需要写一个适配器来转换:

    //首先,需要实现向转换成类型的接口,也就是客户所期望看到的接口
    public class TurkeyAdapter implements Duck {
    
        Turkey turkey;
    
        //去的要 适配的对象的引用,此处使用构造器来进行获取
        public TurkeyAdapter(Turkey turkey) {
            this.turkey = turkey;
        }
    
        //接下来要实现接口中的所有方法,并将不同的方法进行调用与转换
        @Override
        public void quack() {
            turkey.gobble();
        }
    
        @Override
        public void fly() {
            for (int i=0;i<5;i++){
                //因为火鸡飞的距离很短,所以需要连续调用5次,来与鸭子飞行的距离对应
                turkey.fly();
            }
        }
    }

    测试适配器

    public class DuckTestDrive {
    
        public static void main(String[] args) {
            MallardDuck mallardDuck=new MallardDuck();
    
            WildTurkey wildTurkey=new WildTurkey();
            Duck turkeyAdapter=new TurkeyAdapter(wildTurkey);
    
            System.out.println("The Turkey says:...");
            wildTurkey.gobble();
            wildTurkey.fly();
    
            System.out.println("The Duck says...");
            mallardDuck.quack();
            mallardDuck.fly();
    
            System.out.println("The TurkeyAdapter says...");
            testDuck(turkeyAdapter);
        }
    
        //客户需求方法,要测试一个鸭子叫和飞
        private static void testDuck(Duck duck) {
            duck.quack();
            duck.fly();
        }
    }

    输出:

    2.适配器模式解析

    2.1 适配器模式过程配置

     客户使用适配器的过程

    1.客户通过目标接口调用适配器的方法对适配器发出请求

    2.适配器使用被适配者接口把请求转换成被适配者的一个或多个调用接口

    3.客户在接收到调用的结果,但并未察觉这一切是适配器在起转换作用。

    问题1:一个适配器需要做多少“适配”工作?如果需要实现一个很大的目标接口,似乎有很多工作要做?

    回答:实现一个适配器所需要进行的工作,和目标接口的大小成正比。如果不用适配器,就必须改写客户端的代码来调用这个新的接口,将会花许多力气来做大量的调查工作和代码改写工作。相比之下,提供一个适配器类,将所有的改变封装在一个类中,是比较好的做法。

    问题2:一个适配器只能封装一个类吗?

    回答:适配器模式的工作是将一个接口转换成另一个。虽然大多数的适配器模式所采取的的例子都是让一个适配器包装一个被适配者。当需要一个适配器包装多个被适配者的时候,这涉及到另一个模式,被称为外观模式

    问题3:如果系统中 新旧并存,旧的部分期望旧的厂商接口,但是已经使用新厂商的接口编写了一部分,这个时候该怎么办?此处用了适配器,那里却使用未包装的接口,让人觉得混乱。

    回答:可以创建一个双向的适配器,支持两边的接口。想创建一个双向的适配器,就必须实现所涉及的两个接口,这个适配器可以当做旧的接口,或者当做新的接口使用。

    2.2 定义适配器模式

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

    适配器模式可以通过创建适配器进行接口转换,让不兼容的接口变成兼容。这可以让客户从实现的接口解耦。如果在一段时间后,想要改变接口,适配器可以将改变的部分封装起来,客户就不必为了应对不同的接口而每次跟着修改。

    适配器模式的运行时类图为:

    (1)目标(Target)——客户所期待得到的接口,目标可以是具体的或抽象的类,也可以是接口。

    (2)源\被适配者(Adaptee)——已经存在的、需要适配的类。源可以是具体的或抽象的类,也可以是接口。

    (3)适配器(Adapter)——适配器是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是实类。

    2.3 对象和类的适配器

    有“两种”适配器:“对象”适配器和“类”适配器。上面2.2中的对象类图是“对象”适配器的图,本节来讲“类”适配器:

    需要多重继承才能实现它,但是Java中不支持多继承。但是当使用多重继承语言的时候,还是可能会遇到这样的需求。<注:此处指的是 支持多重继承语言的 语言,而不是java>

    类适配器不是使用组合来适配 被适配者, 而是继承 被适配者 和目标类

     位移的差别在于 适配器继承了Target和Adaptee。而对象适配器利用组合的方法将请求传给被适配者。

     对象适配器和类适配器分别使用两种不同的适配方法(分别是组合与继承)。推荐使用 对象适配器

    2.4 枚举适配器

    旧世界的枚举器:早期的集合(Collection)类型(例如,Vector、Stack、Hashtable)都实现了一个名为elements()的方法。该方法会返回一个Enumeration(枚举)。这个Enumeration接口可以注意走过此集合内的每个元素,而无需知道他们在集合内是如何被管理的。

    新世界的迭代器:当Sun推出更新后的集合类时,开始使用Iterator(迭代器)接口,这个接口和枚举接口很像,都可以遍历此集合类型内的每个元素,但不同的是,迭代器还提供了删除元素的能力。

     而今天:我们经常面对遗留代码,这些代码将暴露枚举器接口,但是有希望在新的代码中只使用迭代器,想解决这个问题,我们需要构造一个枚举适配器来将枚举器接口,转换成迭代器接口:

    先看看这两个接口,找出他们的方法映射关系,即:要找出每一个适配器方法在适配者中的对应方法是什么

     设计适配器

    适配器类应该是:需要一个适配器,实现了目标接口,而此目标接口是由被适配者所组合的。hasNext()和next()方法还是很容易实现的,直接把他们从目标对应到被适配者就可以了。目前类图为:

     处理remove()方法

    枚举不支持删除,因为枚举是一个“只读”接口适配器无法实现一个有实际功能的remove()方法,最多只能抛出一个运行时异常。幸运地,迭代器接口的设计者事先料到了这样的需要,所以将remove()方法定义成会抛出UnsupportedOpeartionException。
    在这个例子中,我们看到了适配器并不完美,客户必须小心潜在的异常,但只要客户够小心,而且适配器的文档能做出说明,这也算是一个合理的解决方案。

    编写一个EnumeratorIterator适配器

     2.5 装饰者与适配器的差异

    装饰者模式:装饰者模式的工作都是和“责任”相关的。一旦涉及到装饰者,就表示有一些新的行为或责任要加入到设计中。

    适配器模式:将被适配者 转换成 目标对象,将被适配者里面的方法与所需的目标对象在适配器中进行对应。

    3.外观模式

    适配器模式是如何将一个类的接口转换成另一个符合客户期望的接口的。在Java中要做到这一点,必须将一个不兼容接口的对象包装起来,变成兼容的对象。

    外观模式(Facade-Pattern),改变接口的原因是为了简化接口,它将一个或数个类的复杂的一切都隐藏在背后,只显露出一个干净美好的外观。

     3.1 需求引入

    需求:建立自己的家庭影院。这套系统里包含:内含DVD播放器、投影机、自动屏幕、环绕立体声,还有爆米花机。

    这些组件的组成:

     观赏电影(用困难的方式):在看电影之前,必须要执行一些任务:

    1. 打开爆米花机
    2. 开始爆米花
    3. 将灯光调暗
    4. 放下屏幕
    5. 打开投影机
    6. 将投影机的输入切换到DVD
    7. 将投影机设置在宽屏模式
    8. 打开功放
    9. 将功放的输入设置为DVD
    10. 将功放设置为环绕立体声
    11. 将功放音量调到中(5)
    12. 打开DVD播放器
    13. 开始播放DVD

    将这些任务写成类和方法的调用

    麻烦不止这样:

    1.  看完电影后,你还要把一切都关掉,怎么办?难道要反向地把这一切动作再进行一次?
    2. 如果要听CD或者广播,难道也会这么麻烦?
    3. 如果你决定要升级你的系统,可能还必须重新学习一套稍微不同的操作过程。

    外观模式来解决这团混乱。。。

    3.2 外观模式解决问题

    首先看看外观如何运作:

    1.为家庭影院系统创建一个外观,HomeThearerFacade的心累,它对外暴露出几个简单的方法,比如watchMovie()。

    2.这个外观类将家庭影院的诸多组件视为一个子系统,通过调用这个子系统,来实现watchMovice()方法。

    3.客户代码可以调用此家庭影院外观所提供的方法,而不必再调用这个子系统的方法。因此,想要看电影,只要调用一个方法(也就是watchMovice())就可以了。灯光、DVD播放器、投影机、供方、屏幕、爆米花,这些一口气全部搞定。

    4.外观只是提供给客户更直接的操作,而没有将原来的子系统阻隔起来。如果需要子系统类的更高层功能,还是可以使用原来的子系统。

     

     问1:如果外观封装了子系统的类,那么需要底层功能的客户如何接触这些类?

    答1:外观没有“封装”子系统的类,外观只提供简化的接口。所以客户如果觉得有必要,依然可以直接使用子系统的类。这是外观模式一个很好的特征:提供简化的接口的同时,依然将系统完整的功能暴露出来,以供需要的人使用。

    :外观会新增功能吗,或者它只是将每一个请求转由子系统执行?
    :外观可以附加“聪明的”功能,让使用子系统更方便。比方说,虽然你的穿庭影院外观没有实现任何新行为,但是外观却够聪明,知道爆米花机要先开启然后才能开始爆米花(同样,也要先开机才能放电影)。

    外观不只是简化了接口,也将客户从组件的子系统中解耦。

    外观和适配器可以包装许多类,但是外观的意图是简化接口,适配器的意图是将接转换成不同接口

    3.3 构建家庭影院外观

    1.第一步是使用组合让外观能够访问子系统中所有的组件:

    public class HomeTheaterFacade {
        //组合:将会用到的子系统组件全部做好成员引用
        Amplifier amplifier;
        Tuner tuner;
        CdPlayer cdPlayer;
        Projector projector;
        TheaterLights lights;
        Screen screen;
        PopcornPopper popcornPopper;
    
        //外观将子系统中每一个组件的引用都传入它的构造器中,外观将他们赋值给相应的实例变量
        public HomeTheaterFacade(Amplifier amplifier,
                                 Tuner tuner,
                                 CdPlayer cdPlayer,
                                 Projector projector,
                                 TheaterLights lights,
                                 Screen screen,
                                 PopcornPopper popcornPopper) {
            this.amplifier = amplifier;
            this.tuner = tuner;
            this.cdPlayer = cdPlayer;
            this.projector = projector;
            this.lights = lights;
            this.screen = screen;
            this.popcornPopper = popcornPopper;
        }
    
        //其他方法
    
    
    
    
    }

    2.实现简化的接口:

    现在将子系统的组件整合成一个统一的接口,来实现watchMovie()和endMovie()方法:

    public void watchMovie(String movie) {
            System.out.println("Get ready to watch a movie...");
            popper.on();
            popper.pop();
            lights.dim(10);
            screen.down();
            projector.on();
            projector.wideScreenMode();
            amp.on();
            amp.setStreamingPlayer(player);
            amp.setSurroundSound();
            amp.setVolume(5);
            player.on();
            player.play(movie);
        }
    
    
        public void endMovie() {
            System.out.println("Shutting movie theater down...");
            popper.off();
            lights.on();
            screen.up();
            projector.off();
            amp.off();
            player.stop();
            player.off();
        }

    3. 用轻松的方式来观赏电影

    public class HomeTheaterTestDrive {
    	public static void main(String[] args) {
    		//实例化组件
    		Amplifier amp = new Amplifier("Amplifier");
    		Tuner tuner = new Tuner("AM/FM Tuner", amp);
    		StreamingPlayer player = new StreamingPlayer("Streaming Player", amp);
    		CdPlayer cd = new CdPlayer("CD Player", amp);
    		Projector projector = new Projector("Projector", player);
    		TheaterLights lights = new TheaterLights("Theater Ceiling Lights");
    		Screen screen = new Screen("Theater Screen");
    		PopcornPopper popper = new PopcornPopper("Popcorn Popper");
     		//根据子系统所有的组件来实例化外观
    		HomeTheaterFacade homeTheater = 
    				new HomeTheaterFacade(amp, tuner, player, 
    						projector, screen, lights, popper);
     		//使用简化的接口,先开启电影然后再关闭电影
    		homeTheater.watchMovie("Raiders of the Lost Ark");
    		homeTheater.endMovie();
    	}
    }

    输出结果:

    3.4 定义外观模式

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

    外观模式的意图是要 提供一个简单的接口,好让一个子系统更易于使用

     3.5 “最少知识”原则

    最少知识原则:减少对象之间的交互,只留下几个“密友”。  只和你的密友谈话。

    这到底是什么意思?这是说,当你正在设计一个系统,不管是任何对象,你都要注意它所交互的类有哪些,并注意它和这些类是如何交互的。

    这个原则希望我们在设计中、不要让太多的类耦合在一起、免得修改系统中一部分,会影响到其他部分。如果许多类之间相互依赖,那么这个系统就会变成一个易碎的系统,它需要花许多成本维护,也会因为太复杂而不容易被其他人了解。

    如何不要赢得太多的朋友和影响太多的对象?

    该原则提供了一些方针:就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:

    1. 该对象本身
    2. 被当做方法的参数而传递进来的对象
    3. 此方法所创建或实例化的任何对象
    4. 对象的任何组件

    方针1-3告诉我们,如果某对象是调用其他的方法的返回结果,不要调用该对象的方法

    方针4告诉我们,把“组件”想象成是被实例变量所引用的任何对象,把这想象成是“有一个”(has-a)的关系。

    比如说:

     将方法调用保持在界限内

    问:采用最少知识原则有什么缺点吗?
    :是的,虽然这个原则减少了对象之间的依赖,研究显示这会减少软件的维护成本;但是采用这个原则也会导致更多的“包装”类被制造出来,以处理和其他组件的沟通,这可能会导致复杂度和开发时间的增加,并降低运行时的性能。

    4.总结

    1. 当需要使用一个现有的类而其接口并不符合你的需要时,就使用适配器。
    2. 当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观。
    3. 适配器改变接口以符合客户的期望。
    4. 外观将客户从一个复杂的子系统中解耦。
    5. 实现一个适配器可能需要一番功夫,也可能不费功夫,视目标接口的大小与复杂度而定。
    6. 实现一个外观,需要将子系统组合进外观中,然后将工作委托给子系统执行。
    7. 适配器模式有两种形式;对象适配器和类适配器。类适配器需要用到多重继承。
    8. 你可以为一个子系统实现一个以上的外观。
    9. 适配器将一个对象包装起来以改变其接口,装饰者将一个对象包装起来以增加新的行为和责任,而外观将一群对象“包装”起来以简化其接口。
       

    展开全文
  •  第一眼看到适配器模式,我第一反应就是怎么跟外观模式有点像,仔细看完之后,发现做法上是不一样的。 针对适配器模式,笔记本电脑跟显示器需要一根转接线才能连接,而笔记本电脑或者显示器(Client)都依赖于转接...

                                   

                 

     第一眼看到适配器模式,我第一反应就是怎么跟外观模式有点像,仔细看完之后,发现做法上是不一样的。

    针对适配器模式,笔记本电脑跟显示器需要一根转接线才能连接,而笔记本电脑或者显示器(Client)都依赖于转接线这个适配器(Adaptar),而转接线的两个接口(Target)分别适配笔记本电脑跟显示器的接口,让两者相互适配(Adaptee)。当然了,在设计代码过程中,不应该本末倒置,适配器应该是在匹配接口对不上时才使用,比如两套程序相互可能接口无法对接上,那么使用适配器是很好的。但是如果是在同一个程序中就需要考虑适配器,那么这个程序就应该统一接口方式,而不是考虑适配器。

    而外观模式,其实就好像师傅带学徒(可以当做新开发的类),师傅脑海中有许多技巧(类方法),师傅充当一个外观可以按照自己想法给学徒制定一个学习计划,会让学徒少走弯路。而学徒当然也可以自学师傅的那些技巧,但是少了师傅这个环节一切要靠自己会比较艰难。

    所以说适配器模式和外观模式两者还是有区别的。

    总结自:《大话设计模式》适配器模式

    展开全文
  • 7.适配器模式与装饰者模式 7.1 为什么需要适配器模式 我下面举一个简单的例子帮助大家理解为何使用适配器模式 如果我们欧洲的国家购买了美国生产的电脑,那么他们还需要额外的使用一个交流电的适配器,原因如下图所...

    上一篇:《命令模式》

    7.适配器模式与装饰者模式

    7.1 为什么需要适配器模式

    我下面举一个简单的例子帮助大家理解为何使用适配器模式

    如果我们欧洲的国家购买了美国生产的电脑,那么他们还需要额外的使用一个交流电的适配器,原因如下图所示:
    在这里插入图片描述

    通过上图我们可以看出适配器的作用就是它位于美式插头和欧式插头中间,其工作就是将欧式插座转换成美式插座,使美式的插头可以插进去,简单来说就是适配器改变了插座的接口,已符合美式笔记本的需求。
    某些交流电适配器相当简单,它们只是改变插座的形状来匹配你的插头,直接把电流传送过去。但是有些适配器内部则是相当复杂,可能会改变电流符合装置的需求。

    而我们接下来所学到的面向对象的适配器原则就是:将一个接口转换成另一个接口,以符合用户的期望

    7.2 面向对象适配器

    假设已有一个软件系统,你希望它能和一个新的厂商类库搭配使用,但是这个新厂商所设计出来的接口,不同于旧厂商的接口:
    在这里插入图片描述

    你不想改变现有的代码,解决这个问题(而且你也不能改变厂商的代码)。所以该怎么做
    在这里插入图片描述

    适配器就像是一个中间人,他将客户所发出的请求转换成厂商类能理解的请求
    在这里插入图片描述

    下面我们通过一个具体的实例去看看适配器是具体怎么工作的
    我们现在有个一个鸭子对象

    public interface Duck {
        /**
         * 所有的鸭子都具有两种行为
         **/
        //1.呱呱叫
        public void quack();
    
        //2.飞行行为
        public void fly();
    }
    
    

    绿头鸭是鸭子的子类

    /**
     * 绿头鸭
     */
    public class MallardDuck implements Duck {
    
        @Override
        public void quack() {
            System.out.println("呱呱叫");
        }
    
        @Override
        public void fly() {
            System.out.println("我会飞");
        }
    }
    
    

    接下来我们引入火鸡类

    public interface Turkey {
        //只会咯咯叫
        void gobble();
    
        //会飞
        void fly();
    }
    
    public class WildTurkey implements Turkey{
        @Override
        public void gobble() {
            System.out.println("咯咯叫");
        }
    
        @Override
        public void fly() {
            System.out.println("我会飞一小段距离");
        }
    }
    

    现在,假设你缺鸭子对象,想用一些火鸡对象来冒充。显而易见,因为火鸡的接口不同,所以我们不能公然拿来用。
    为了使火鸡接口能够适配我们的鸭子模型,所以我们需要一个火鸡接口的适配器

    /**
     * 首先,我们需要实现想转换成的类型接口,也就是你的客户所期望看到的接口。
     */
    public class TurkeyAdapter implements Duck {
        Turkey turkey;
    
        //接着,需要取得适配的对象引用,这里我们利用构造器取得这个引用。
        public TurkeyAdapter(Turkey turkey) {
            this.turkey = turkey;
        }
    
        @Override
        public void quack() {
            turkey.gobble();
        }
    
        /**
         * 显然两个接口都具备了fly()方法,火鸡的飞行距离很短,
         * 不像鸭子可以长途飞行。主要让鸭子的飞行和火鸡的飞行能够对应.必须连续五次调用火鸡的fly()来完成。
         */
        @Override
        public void fly() {
            for (int i = 0; i < 5; i++) {
                turkey.fly();
            }
    
        }
    }
    
    

    测试:

    public class DuckTestDriver {
        public static void main(String[] args) {
            /**先创建一只鸭子和一只火鸡**/
            MallardDuck duck = new MallardDuck();
            WildTurkey turkey = new WildTurkey();
            /**将火鸡包装进一个火鸡适配器中,使他看起来像一只鸭子**/
            Duck turkeyAdapter = new TurkeyAdapter(turkey);
            /**测试这只火鸡,让他咯咯叫**/
            System.out.print("火鸡叫声:");
            turkey.gobble();
            System.out.print("鸭子叫声:");
            duck.quack();
            System.out.print("使用适配器的鸭子叫声:");
            turkeyAdapter.quack();
            System.out.println("-----------使用适配器的鸭子飞行行为:-------------");
            turkeyAdapter.fly();
    
        }
    }
    
    

    测试结果如下:
    在这里插入图片描述

    7.3 适配器解析

    现在我们已经知道什么是适配器了,让我们后退一步,再次看看各部分之间的关系。
    在这里插入图片描述

    客户使用适配器的过程如下:

    • 1.客户通过目标接口调用适配器的方法对适配器发出请求。
    • 2.适配器使用被适配者接口把请求转换成被适配者的一个或多个调用接口。
    • 3.客户接收到调用的结果,但并未察觉这一切是适配器在起转换作用。

    7.4 适配器模式的定义

    在这里插入图片描述

    这个模式可以通过创建适配器进行接口转换,让不兼容的接口变成兼容。这可以让客户从实现的接口解耦。如果在一段时间之后,我们想要改变接口,适配器可以将改变的部分封装起来,客户就不必为了应对不同的接口而每次跟着修改。
    在这里插入图片描述

    7.5 对象和类的适配器

    实际上有两种适配器:对象适配器,类适配器;
    在前面的叙述中,我们已经描述了对象适配器。
    而类适配器:
    在这里插入图片描述

    唯一的差别就在于类适配器继承了Target和Adaptee。而对象适配器利用组合的方式将请求传送给被适配者。

    7.6 枚举器和迭代器的适配

    枚举器:
    在这里插入图片描述

    迭代器:
    在这里插入图片描述

    接下来我们尝试将枚举器适配到迭代器上
    在这里插入图片描述

    设计适配器

    这个类应该是这样的:我们需要一个适配器,实现了目标接口,而此目标接口是由被适配者所组合的。hasNext()和next()方法很容易实现,直接把它们从目标对应到被适配者就可以了。但是对于remove()方法,我们又该怎么办?目前,类图是这样的:
    在这里插入图片描述

    处理remove()方法

    我们知道枚举不支持删除,因为枚举是一个“只读”接口。适配器无法实现一个有实际功能的remove()方法,最多只能抛出一个运行时异常。幸运地,迭代器接口的设计者事先料到了这样的需要,所以将remove()方法定义成会抛出UnsupportedOpeartionException。
    在这个例子中,我们看到了适配器并不完美,客户必须小心潜在的异常,但只要客户够小心,而且适配器的文档能做出说明,这也算是一个合理的解决方案。
    接下来我们开始编写EnumeratorIterator

    /**
     * 因为我们将枚举追配成迭代器,适配器需要实现迭代器接口
     * 适配器必须看起来就像是一个迭代器。
     */
    public class EnumeratorIterator implements Iterator {
        Enumeration enumeration;
    
        /**
         * 我们利用组合的方式,将枚举组合进入适配器中,所以用一个实例变量记录枚举。
         *
         * @param enumeration
         */
        public EnumeratorIterator(Enumeration enumeration) {
            this.enumeration = enumeration;
        }
    
        /**
         * 选代器的hasNext()方法其实是委托给枚举的hasMoreElements()方法。
         *
         * @return
         */
        @Override
        public boolean hasNext() {
            return enumeration.hasMoreElements();
        }
    
        /**
         * 而选代器的next()方法其实是委托给枚举的nextElement()方法
         *
         * @return
         */
        @Override
        public Object next() {
            return enumeration.nextElement();
        }
    
        /**
         * 很不幸,我们不能支持选代器的remove()方法,所以必须放弃。
         * 在这里、我们的做法是抛出一个异常
         */
        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
    
    

    接下来我们做个测试:

    public class EnumerationIteratorTestDrive {
        public static void main(String[] args) {
            Integer[] list = new Integer[]{1, 2, 3, 4, 5};
            Vector<Integer> v = new Vector<Integer>(Arrays.asList(list));
            Iterator<?> iterator = new EnumeratorIterator(v.elements());
            while (iterator.hasNext()) {
                System.out.print(iterator.next());
                System.out.print("  ");
            }
    
        }
    }
    
    

    学到此处,你已经知道适配器模式是如何将一个类的接口转换成另一个符合客户期望的接口的。你也知道在Java中要做到这一点,必须将一个不兼容接口的对象包装起来,变成兼容的对象。
    我们现在要看一个改变接口的新模式,但是它改变接口的原因是为了简化接口。这个模式被巧妙地命名为外观模式(Facade-Pattern),之所以这么称呼,是因为它将一个或数个类的复杂的一切都隐藏在背后,只显露出一个干净美好的外观。
    在这里插入图片描述

    接下来我们通过一个简单的例子让展示外观模式的强大之处
    有一套系统,内含DVD播放器、投影机、自动屏幕、环绕立体声,甚至还有爆米花机。
    接下来就是开始观看电影,但是在观看之前,你需要做以下事情:
    在这里插入图片描述

    但是你将会面临以下麻烦:

    • 看完电影后,你还要把一切都关掉,怎么办?难道要反向地把这一切动作再进行一次?
    • 如果要听CD或者广播,难道也会这么麻烦?
    • 如果你决定要升级你的系统,可能还必须重新学习一套稍微不同的操作过程。

    怎么办?使用你的家庭影院竟变得如此复杂!让我们看看外观模式如何解决这团混乱,好让你能轻易地享受电影……

    7.7 灯光 相机 外观

    你需要的正是一个外观:有了外观模式,通过实现一个提供更合理的接口的外观类,你可以将一个复杂的子系统变得容易使用。如果你需要复杂子系统的强大威力,别担心,还是可以使用原来的复杂接口的;但如果你需要的是一个方便使用的接口,那就使用外观。
    在这里插入图片描述

    现在,你的客户代码可以调用此家庭影院外观所提供的方法,而不必再调用这个子系统的方法。所以,想要看电影,我们只要调用一个方法(也就是watchMovie())就可以了。灯光、CVD播放器、投影机,屏幕幕、爆米花,一口气全部搞定。
    外观只是提供你更直接的操作,未将原来的子系统阻隔起来。如果你需要子系统类的更高层功能,还是可以使用原来的子系统。
    外观不只是简化了接口,也将客户从组件的子系统中解耦。
    外观和适配器可以包装许多类,但是外观的意图是简化接口,而适配器的意图是将接口转换成不同接口。
    接下来我们开始构造家庭影院的外观:

    public class HomeTheaterFacade {
        Amplifier amp;//扩音器
        Tuner tuner;//广播
        StreamingPlayer player;//流媒体播放器
        CdPlayer cd;//cd
        Projector projector;//投影仪
        TheaterLights lights;//剧院灯光
        Screen screen;//屏幕
        PopcornPopper popper;//爆米花
    
        public HomeTheaterFacade(Amplifier amp,
                                 Tuner tuner,
                                 StreamingPlayer player,
                                 Projector projector,
                                 Screen screen,
                                 TheaterLights lights,
                                 PopcornPopper popper) {
    
            this.amp = amp;
            this.tuner = tuner;
            this.player = player;
            this.projector = projector;
            this.screen = screen;
            this.lights = lights;
            this.popper = popper;
        }
    
        /**
         * 看电影
         *
         * @param movie
         */
        public void watchMovie(String movie) {
            System.out.println("Get ready to watch a movie...");
            popper.on();
            popper.pop();
            lights.dim(10);
            screen.down();
            projector.on();
            projector.wideScreenMode();
            amp.on();
            amp.setStreamingPlayer(player);
            amp.setSurroundSound();
            amp.setVolume(5);
            player.on();
            player.play(movie);
        }
    
        /**
         * 结束电影
         */
        public void endMovie() {
            System.out.println("Shutting movie theater down...");
            popper.off();
            lights.on();
            screen.up();
            projector.off();
            amp.off();
            player.stop();
            player.off();
        }
    
        /**
         * 听广播
         *
         * @param frequency
         */
        public void listenToRadio(double frequency) {
            System.out.println("Tuning in the airwaves...");
            tuner.on();
            tuner.setFrequency(frequency);
            amp.on();
            amp.setVolume(5);
            amp.setTuner(tuner);
        }
    
        /**
         * 结束广播
         */
        public void endRadio() {
            System.out.println("Shutting down the tuner...");
            tuner.off();
            amp.off();
        }
    }
    
    

    至于里面用到的组件,我就不在此赘述,点击此处下载
    在这里插入图片描述

    接下来我们进行测试

    public class HomeTheaterTestDrive {
        public static void main(String[] args) {
            Amplifier amp = new Amplifier("Amplifier");
            Tuner tuner = new Tuner("AM/FM Tuner", amp);
            StreamingPlayer player = new StreamingPlayer("Streaming Player", amp);
            CdPlayer cd = new CdPlayer("CD Player", amp);
            Projector projector = new Projector("Projector", player);
            TheaterLights lights = new TheaterLights("Theater Ceiling Lights");
            Screen screen = new Screen("Theater Screen");
            PopcornPopper popper = new PopcornPopper("Popcorn Popper");
    
            HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade(amp, tuner, player,
                    projector, screen, lights, popper);
            homeTheaterFacade.watchMovie("Raiders of the Lost Ark");
            homeTheaterFacade.endMovie();
        }
    
    
    }
    
    

    运行结果如下:
    在这里插入图片描述

    7.8 外观模式的定义

    想要使用外观模式,我们创建了一个接口简化而统一的类,用来包装子系统中一个或多个复杂的类。
    外观模式相当直接,很容易理解,这方面和许多其他的模式不太一样。但这并不会降低它的威力:外观模式允许我们让客户和子系统之间避免紧耦合,而且稍后你还会看到,外观模式也可以帮我们遵守一个新的面向对象原则。
    在这里插入图片描述

    从下图我们可以很直观的理解外观模式的意图就是提供一个简单的接口,好让一个子系统更易于使用。
    在这里插入图片描述

    7.9 最少知识原则

    最少知识(Least Knowledge)原则告诉我们要减少对象之间的交互,只留下几个“密友”。
    也就是说,当你正在设计一个系统,不管是任何对象,你都要注意它所交互的类有哪些,并注意它和这些类是如何交互的。
    这个原则希望我们在设计中,不要让太多的类耦合在一起,免得修改系统中一部分,会影响到其他部分。如果许多类之间相互依赖,那么这个系统就会变成一个易碎的系统,它需要花许多成本维护,也会因为太复杂而不容易被其他人了解。

    7.10 要点

    • 当需要使用一个现有的类而其接口并不符合你的需要时,就使用适配器。
    • 当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观。
    • 适配器改变接口以符合客户的期望。
    • 外观将客户从一个复杂的子系统中解耦。
    • 实现一个适配器可能需要一番功夫,也可能不费功夫,视目标接口的大小与复杂度而定。
    • 实现一个外观,需要将子系统组合进外观中,然后将工作委托给子系统执行。
    • 适配器模式有两种形式:对象适配器和类适配器。类适配器需要用到多重继承。
    • 适配器将一个对象包装起来以改变其接口:装饰者将一个对象包装起来以增加新的行为和责任;而外观将一群对象“包装”起来以简化其接口。

    7.11 设计原则

    封装变化
    多用组合,少用继承
    针对接口编程,不针对实现编程
    为交互对象之问的松耦合设计而努力
    类应该对扩展开放,对修改关闭。
    依赖抽象,不要依赖具体类。、
    只和朋友交谈
    在这里插入图片描述
    下一篇 《模板方法模式》

    展开全文
  • 适配器模式  所谓适配器模式,将一个类的接口,转换为客户所期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。  适配器主要组成包括:  目标接口:客户端所希望得到的接口  适配器:这个主要...
  • 1.适配器模式与桥接模式的区别和联系适配器模式和桥接模式都是间接引用对象,因此可以使系统更灵活,在实现上都涉及从自身以外的一个接口向被引用的对象发出请求。两种模式的区别在于使用场合不同,适配器模式主要...
  • 实验7 适配器模式外观模式与模板方法模式---Java设计模式
  • 该资源是学习完设计模式的适配器模式与外观模式根据书中内容所写的demo
  • 适配器模式 现实中的适配器 以前的手机USB数据线连接手机大多是老式的梯形microUSB接口, 而现在连接大多数手机都采用了速度更快typeC椭圆形接口, 以前的旧数据线还想继续使用怎么办呢? 配一个microUSB转typeC的转...
  • 9. 适配器模式外观模式以及装饰者模式之间的区别。 1. 生活中的适配器 上图,中间的适配器改变了插座的接口,最后成功让电脑能够使用充电。 接下来让我们看看,现有系统、适配器和厂商类之间的关系。 2....
  • I . 适配器模式概念 ... 适配器模式 外观模式对比 V . 适配器模式 相关角色 ( 重点 ) VI . 适配器模式 ( 类适配器 ) 代码实现流程 ( 重点 ) VII . 适配器模式 ( 对象适配器 ) 代码实现流程 ( 重点 )
  • 当需要用一个现有的类而其接口并不符合你的需要时就用适配器。 首先来个类图: 这个类图够简单但是充满了良好的OO设计原则,使用对象组合,以修改的接口包装被适配者:被适配者的任何子类都可以搭配着适配器使用...
  • 适配器模式 场景描述:想象一下我们维护了一套老系统,并于一个厂商通过接口进行交互。但是最近厂商更新它们的代码,并变更了接口格式,我们如何在不修改老系统代码的基础上,优雅的过渡呢? 提出方案:我们可以想象...
  • 本章介绍设计模式中的 适配器模式、桥接模式、代理模式、装饰者模式
  • 主要介绍了Java结构型设计模式中的适配器模式与桥接模式,结构型设计模式是从程序的结构上解决模块之间的耦合问题,需要的朋友可以参考下
  • 定义外观模式3. 总结 1. 定义适配器模式 适配器模式:将一个类的接口,转换成客户期望的另外一个接口。适配器让原本接口不兼容的类可以合作无间 对象适配器就是使用组合,类适配器就是使用多重继承 1.1 对象适配器 ...
  • 一、适配器与外观模式 适配器模式:将一个类的接口,转换成客户期待的另一个接口,适配器让原本接口不兼容的类可以合作无间。 外观模式:提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层...
  • 1.模式定义 命令模式: 将“请求”封装为对象,以便使用不同的请求,队列或者日志来参数化其他对象。 命令模式也支持可撤销的操作。...适配器模式包含两种:类适配器,对象适配器,分别对应继承,组合实现。
  • 辨析代理模式、外观模式适配器模式三者区别

    千次阅读 热门讨论 2014-06-29 17:27:35
    代理模式 定义:为其他对象提供一种代理以控制对...外观模式 定义:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 UML图: 小例子:就好比有一远道
  • 适配器模式 结构 目标抽象类(定义目标服务所需要的接口,) 适配器类(是一个转换器,对目标接口和适配者进行适配) 适配者类(目标服务需要的业务方法) 简单示例 例:某公司开发一款玩具汽车,玩具汽车支持在...
  • 设计模式之适配器模式

    千次阅读 2022-01-22 21:18:31
    根据适配器类适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器适配者之间是关联关系;在类适配器模式中,适配器适配者之间是继承(或实现)关系。 类型 结构型。 ...
  • 设计模式之结构型模式 一、概述 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合...适配器(Adapter)模式:将一个类的接
  • 实验4适配器组合外观模式方案.pdf 实验4适配器组合外观模式方案.pdf 实验4适配器组合外观模式方案.pdf
  • 一、定义代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。适配器模式(Adapter):将一个类的接口转换成客户希望的另外...二、理解代理模式和适配器模式应该说很相像,但是他们的区别也很明显,...
  • 适配器的作用可以简单通过下图得知,OO适配器就是将一个接口转换成另一个接口,以符合客户的期望。 实际场景应用可以联想插座适配器,如下图所示。 客户使用适配器的过程如下: ① 客户通过目标接口调用适配器的...
  • 目录[设计模式] 适配器模式 + 外观模式适配器模式对象适配器类适配器适配器和装饰者模式外观模式总结更多 手机用户请横屏获取最佳阅读体验,REFERENCES中是本文参考的链接,如需要链接和更多资源,可以关注其他博客...
  • 适配器模式外观者模式一,写在最前面1,为什么要将这两个设计模式写在一起?不仅这两个设计模式都比较简单,而且我们可以通过这两个设计模式更好的理解OO思想。2,在本章节的最后会引入了最少知识设计原则。二,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 31,362
精华内容 12,544
关键字:

外观模式与适配器模式的区别