• 设计模式学习笔记之适配器模式


    什么是适配器模式?

    适配器模式(有时候也称包装样式或者包装)就是将一个类的接口适配成用户所期待的。一个适配同意通常由于接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。

    看一个我们日常生活中的图:




    假设出国旅行,肯定会买一些国外的优质的电器回来,可是国外的电器插头可能是这种。

    而国内的插座确实这种。




    肯定是插不进去的。

    。怎么办呢?神通广大的适配器就该出场了!




    这下应该能够理解适配器是用来干嘛的了吧。事实上设计模式中的适配器模式和这个道理是一样的。

    我们来看一下适配器模式的类图




    PS:我画的可能有点丑。。

    适配器基本的作用就是将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本因为接口不兼容而不能一起工作的那些类能够一起工作。

    以下我们来举一个详细的样例说明一下吧:

    《暮光之城》里的吸血鬼家族。今天晚上要举办一场吸血鬼舞会。一名人类战士吸血鬼研究学者得到消息也想混进去趁机研究一下吸血鬼。可是假设他直接去,那肯定就被吸血鬼们发现了。所以他要伪装一下,以下我们用代码来实现一下




    人类接口


    //人类接口
    public interface Human {
    	//进食
    	public void eat();
    	//运动
    	public void run();
    }
    


    人类战士类


    public class Soldier implements Human {
    
    	@Override
    	public void eat(){
    		// TODO Auto-generated method stub
    		System.out.println("吃饭");
    	}
    
    	@Override
    	public void run(){
    		// TODO Auto-generated method stub
    		System.out.println("跑得非常慢");
    	}
    }


    PS:这里跑得慢,肯定是跟吸血鬼们比較的。这哥们在人类中肯定是精英。


    吸血鬼接口


    //吸血鬼接口
    public interface Vampire {
    	//进食
    	public void suckBlood();
    	//运动
    	public void run();
    }
    

    吸血鬼战士类


    public class VampireWarriors implements Vampire {
    
    	@Override
    	public void suckBlood() {
    		// TODO Auto-generated method stub
    		System.out.println("吸血");
    	}
    
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		System.out.println("跑得非常快");
    	}
    }

    好了以下我们就要对这位人类战士进行一下化妆了

    事实上在适配器模式中。适配有两种方法


    对象适配器模式
    -- 在这样的适配器模式中,适配器容纳一个它包裹的类的实例。在这样的情况下,适配器调用被包裹对象的物理实体。
    类适配器模式
    -- 这样的适配器模式下。适配器继承自已实现的类(一般多重继承 ps:java中能够通过接口多继承)。



    我们先来实现一下:

    对象适配器模式:


    //对象适配模式
    public class SoldierAdapter implements Vampire {
    	
    	//被适配的士兵类
    	private Soldier soldier;
    	
        //在构造函数中传入士兵类
    	public SoldierAdapter(Soldier soldier)
    	{
    		this.soldier=soldier;
    	}
    	
    	//伪装吸血鬼进食
    	@Override
    	public void suckBlood() {
    		// TODO Auto-generated method stub
    		soldier.eat();
    		System.out.println("饭的内容就是血");
    	}
    	
    	//伪装吸血鬼运动,由于跑得慢所以要多跑几次
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		for(int i=0;i<5;i++)
    		{
    			soldier.run();
    		}
    	}
    }
    


    測试一下:

    測试类


    public class MainTest {
    	public static void main(String[] args) {
    		
    		//人类战士
    		Soldier soldier=new Soldier();
    		
    		//吸血鬼战士
    		VampireWarriors vampireWarriors=new VampireWarriors();
    		
    		//伪装的吸血鬼战士
    		Vampire vampire2humanAdapter=new SoldierAdapter(soldier);
    		
    		//人类战士行为
    		System.out.println("人类战士:");
    		soldier.eat();
    		soldier.run();
    		
    		System.out.println();
    		
    		//吸血鬼战士行为
    		System.out.println("吸血鬼战士:");
    		vampireWarriors.suckBlood();
    		vampireWarriors.run();
    		
    		System.out.println();
    		
    		//伪装者的行为
    		System.out.println("人类战士冒充吸血鬼战士:");
    		vampire2humanAdapter.suckBlood();
    		vampire2humanAdapter.run();	
    	}
    }




    还不错,但愿吸血鬼发现不了这个兄弟。


    以下我们来实现一下类适配器模式


    //类适配器模式
    public class SoldierAdapter2 extends Soldier implements Vampire {
    	
    	//伪装吸血鬼的行为
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		for(int i=0;i<5;i++)
    		{
    			super.run();
    		}
    	}
    
    	@Override
    	public void suckBlood() {
    		// TODO Auto-generated method stub
    		super.eat();
    		System.out.println("饭的内容就是血");
    	}
    }

    測试一下


    public class MainTest {
    	public static void main(String[] args) {
    		
    		//人类战士
    		Soldier soldier=new Soldier();
    		
    		//吸血鬼战士
    		VampireWarriors vampireWarriors=new VampireWarriors();
    		
    		//伪装的吸血鬼战士
    		Vampire vampire2humanAdapter=new SoldierAdapter2();//这里就不用传入对象了
    		
    		//人类战士行为
    		System.out.println("人类战士:");
    		soldier.eat();
    		soldier.run();
    		
    		System.out.println();
    		
    		//吸血鬼战士行为
    		System.out.println("吸血鬼战士:");
    		vampireWarriors.suckBlood();
    		vampireWarriors.run();
    		
    		System.out.println();
    		
    		//伪装者的行为
    		System.out.println("人类战士冒充吸血鬼战士:");
    		vampire2humanAdapter.suckBlood();
    		vampire2humanAdapter.run();	
    	}
    }




    结果是一样的啦


    我们比較一下对象适配器是类适配器:


    类适配器:
    因为适配器类是适配者类的子类,因此能够再适配器类中置换一些适配者的方法,使得适配器的灵活性更强。

    可是对于Java、C#等不支持多重继承的语言,一次最多仅仅能适配一个适配者类。并且目标抽象类仅仅能为接口。不能为类,其使用有一定的局限性,不能将一个适配者类和他的子类同一时候适配到目标接口。


    对象适配器:
    把多个不同的适配者适配到同一个目标。也就是说,同一个适配器能够把适配者类和他的子类都适配到目标接口。

    可是,与类适配器模式相比,要想置换适配者类的方法就不easy。


    再来看看适配器模式的长处是 场景

    1、将目标类和适配者类解耦
    2、添加了类的透明性和复用性。将详细的实现封装在适配者类中,对于client类来说是透明的。并且提高了适配者的复用性
    3、灵活性和扩展性都很好,符合开闭原则


    适配器模式的适用场景: 
    1、我们在使用第三方的类库,或者说第三方的API的时候。我们通过适配器转换来满足现有系统的使用需求
    2、我们的旧系统与新系统进行集成的时候,我们发现旧系统的数据无法满足新系统的需求,那么这个时候,我们可能须要适配器,完毕调用需求。















  • 相关阅读:
    jquery ajax 返回数据时 ff正常,ie接受到数据但是显示不了
    查看IIS日志并且分析其中的错误日志
    用eventvwr查看系统日志
    C++实现Trie 树
    [算法之美笔记02] 栈模拟网页的前进后退 ; 阻塞队列与并发队列
    MySQL学习小记(三) 结合JDBC实现用户的登录响应
    [算法之美笔记01] 数组,链表的删除和垃圾回收,缓存机制有什么关系
    [埋坑系列] 基于QT/C++的杰瑞走迷宫小游戏 :1.大体构造
    品味C++实现AVL树的删除操作
    C++实现AVL树的四种旋转
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/7339671.html
Copyright © 2020-2023  润新知