zoukankan      html  css  js  c++  java
  • 装饰模式、代理模式、适配器模式

    简介

    装饰模式、代理模式、适配器模式个人感觉非常相似,三者的类图也差不多,不好理解。

    区别:

    装饰模式:原有功能不能满足现有需求,按照开闭原则的思路,我们通过扩展接口来增强功能。可以装饰多层

    代理模式:通过代理对象来控制访问另一个对象(被代理对象)的方法,不对该方法进行直接操作。

    适配器模式:解决接口不匹配的问题。

    下面通过简单的例子具体说明。

    (1)装饰模式

    场景描述如下:现有接口Car,拥有方法run,其实现类为BMWCar。

    public interface Car {
    
        public void run();
    }
    public class BMWCar implements Car {
        @Override
        public void run() {
            System.out.println("BMW running!");
        }
    }

    测试场景如下

    public class Client {
    
        public static void main(String[] args) {
            Car car = new BMWCar();
            car.run();
        }
    }

    输出:“BMW running!”

    现在需求变了,要求BMWCar在run之前要说一句“Heihei, I am BMW!”(增强功能)。通常情况不建议改变现有的代码,对修改关闭对扩展开放(开闭原则),可行的方案是扩展一个装饰者DecorateCar,DecorateCar也实现了Car接口,并持有Car的引用,然后通过构造函数实例化。

    public class DecorateCar implements Car {
    
        private Car car;
    
        public DecorateCar(Car car){
            this.car = car;
        }
    
        @Override
        public void run() {
            System.out.println("Hiahia, I am BMW!");
            car.run();
        }
    }

    测试场景如下:

    public class Client {
    
        public static void main(String[] args) {
            Car car = new DecorateCar(new BMWCar());
            car.run();
        }
    }

    输出为:

    Hiahia, I am BMW!
    BMW running!

    (2)代理模式

    场景:超级明星都有经纪人,若想邀请该明星演出必须通过经纪人,然后经纪人根据明星的日程表来安排演出,若日程表为满,则拒绝本次邀请。

    超级明星可以用SuperStar接口表示,具体的明星类如歌手用Singer实现SuperStar。经纪人就是代理,用StarProxy表示。

    public interface SuperStar {
    
        public void perform();
    }
    public class Singer implements SuperStar {
        @Override
        public void perform() {
            System.out.println("singing a song!");
        }
    }
    public class StarProxy implements SuperStar {
    
        private SuperStar superStar;
    
        private boolean busyState;
    
        public StarProxy(boolean busyState){
            superStar = new Singer();
            this.busyState = busyState;
        }
    
        @Override
        public void perform() {
            if (busyState){
                superStar.perform();
            }else{
                System.out.println("行程已满,无法演出");
            }
        }
    }

    这里通过代理对象控制访问,当busyState为true时,经纪人(代理)安排明星(被代理)演出,否则不能演出。测试场景如下

    public class Client {
    
        public static void main(String[] args) {
            SuperStar superStar = new StarProxy(true);
            superStar.perform();
    
            superStar = new StarProxy(false);
            superStar.perform();
        }
    }

    输出:

    singing a song!
    行程已满,无法演出

    咋一看,真感觉代理模式和装饰模式没啥区别。但是,请注意两个模式的使用场景不一样,装饰模式目的是添加新的功能,可以装饰很多层,如Java IO就是典型的应用。代理模式一般只代理一次,一般用作控制访问。其实也不用纠结设计模式的名称,我们知道这一类问题如何解决不就ok了。

    (3)适配器模式

    场景:众所周知安卓手机使用安卓充电器(typeC接头),苹果手机使用苹果充电器(iphone接头)。现在你有一台安卓手机和一个苹果充电器,怎么给手机充电。

    答案:使用转接头(适配器)将iphone接头转为typeC接头,就可以用苹果充电器给安卓手机充电。

    安卓充电器通过typeC给手机充电。

    public interface AndroidCharger {
        public void typeC();
    }
    public class AndroidChargerImpl implements AndroidCharger {
        @Override
        public void typeC() {
            System.out.println("我能给手机充电");
        }
    }

    苹果充电器通过iphone给手机充电。

    public interface IphoneCharger {
        public void iphone();
    }
    public class IphoneChargerImpl implements IphoneCharger {
        @Override
        public void iphone() {
            System.out.println("我能给手机充电");
        }
    }

    适配器就是拿苹果充电器当作安卓充电器使用,这样我们就可以通过info来充电。

    public class IphoneAdapter implements AndroidCharger {
        private IphoneCharger iphoneCharger;
    
        public IphoneAdapter(IphoneCharger iphoneCharger){
            this.iphoneCharger = iphoneCharger;
        }
        @Override
        public void typeC() {
            iphoneCharger.iphone();
        }
    }

    测试场景如下

    public class Client {
    
        public static void main(String[] args) {
    
            IphoneCharger iphoneCharger = new IphoneChargerImpl();
            AndroidCharger androidCharger = new IphoneAdapter(iphoneCharger);
            androidCharger.typeC();
        }
    }

    有一个苹果充电器,然后将其适配成安卓充电器,通过typeC来充电。输出如下:

    我能给手机充电

    ------------------------完-------------------------

  • 相关阅读:
    js模板引擎
    浮点数正则表达式
    DbContext SQLite配置文件
    JS中的HTML片段
    WPF 使用HttpListener搭建本地web服务器
    C#调用Windows(8/10)自带的虚拟键盘
    SQLSERVER 设置默认值
    SQLSERVER存储过程基本语法
    MSSQL存储过程
    WPF手动绑定事件
  • 原文地址:https://www.cnblogs.com/ouym/p/9452693.html
Copyright © 2011-2022 走看看