装饰模式、代理模式、适配器模式

简介

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

区别:

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

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

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

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

(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来充电。输出如下:

我能给手机充电

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

猜你喜欢

转载自www.cnblogs.com/ouym/p/9452693.html