适配器模式

所谓适配器模式,就是把一个类的构造转换成另外一个类的接口。使得本来因为接口不兼容而不能工作的类都可能一起工作。

在生活中比拟常见的就是当咱们想连贯显示器的时候,vga须要转成hdmi,还有电源适配,比方可能须要220v的充电头,然而只有110v的充电头,那么就须要将220v的充电头适配成110v的充电头。

Adaptee: 须要适配的就代码,旧接口

Adapter: 将调用转发给Adaptee 的适配器类

Target: 反对的新接口

适配器模式UML

类适配器模式

Target

public interface Target {    void output110v();}

Adaptee

public class Adaptee {    public void output220v() {        System.out.println("输入电压");    }}

Adapter

public class Adapter extends Adaptee implements Target {    @Override    public void output110v() {        this.output220v();    }}

这里须要留神的是Adapter继承了源类而实现了指标类

Client

public class Client {    public static void main(String[] args) {        Target target = new Adapter();        target.output110v();    }}

尽管咱们是应用了output110v的充电头,然而通过Adapter后,最终通过this.output220v() 会调用output220v的充电头,这就是把output220v适配成了output110v

对象适配器模式

其实说得这么高大上,其实就是Adaptor 的实现形式不同,类适配器模式采纳继承了源类(也就是须要适配的类)实现了指标类。

这样就存在一个问题,当咱们须要适配多个类的时候就会呈现问题,因为java中是容许实现多个接口,然而只能继承一个类

为了解决这个问题,咱们能够把须要适配的类作为Adapter 的成员变量,而后通过构造函数进行适配

public class NewAdapter implements Target{    Adaptee adaptee;    public NewAdapter(Adaptee adaptee) {        this.adaptee = adaptee;    }    @Override    public void output110v() {        adaptee.output220v();    }}

代理模式


代理模式也算是比拟罕用的设计模式之一,大家接触最多的spring aop,就是采纳动静代理模式来实现的。代理模式能够分为一般代理模式,强制代理模式,动静代理模式,也是本文着重解说的,当然还有其代理模式。

先来用一段代码来领会代理模式,场景是玩家打游戏。

Subject: 独特接口,客户端应用的现有接口

RealSubject: 实在对象的类

ProxySubject: 代理对象类

代理模式UML

一般代理模式


通过下面的例子,置信对大家都对代理模式有点感觉了,然而如同又不那么失当,下面的测试类种,还是须要新建一个player,这就相当于什么,相当于咱们是在手机上登录了游戏,而后再把手机给代练者代练。而事实上,常常是把账号密码给代练即可。

这就引出了一般代理模式,客户端不能拜访实在角色,只能拜访代理角色,咱们可能晓得代理的存在。

Subject

public interface SubjectNormalGamePlayer {    public void login();    public void upgrade();    public void matches();}

RealSubject

public class RealSubjectNormalPlayerImpl implements SubjectNormalGamePlayer {    private String name;    private String password;    public RealSubjectNormalPlayerImpl(String name, String password) {        this.name = name;        this.password = password;    }    @Override    public void login() {        if(name.equals("cutey") && password.equals("123456")) {            System.out.println(name + "登录胜利");        }    }    @Override    public void upgrade() {          System.out.println(name + "降级");    }    @Override    public void matches() {        System.out.println(name + "打排位赛");    }}

ProxySubject

public class ProxySubjectNormalPlayerImpl implements SubjectNormalGamePlayer {    SubjectNormalGamePlayer gamePlayer;    //留神这里的区别,咱们是拿账号和明码去登录实在角色    //并不是间接拿实在角色的手机来打    public ProxySubjectNormalPlayerImpl(String name, String password) {        gamePlayer = new RealSubjectNormalPlayerImpl(name, password);    }    @Override    public void login() {        System.out.print("代练:");        gamePlayer.login();    }    @Override    public void upgrade() {        System.out.print("代练:");        gamePlayer.upgrade();    }    @Override    public void matches() {        System.out.print("代练:");        gamePlayer.matches();    }}

Client

public class Client {    public static void main(String[] args) {        //通过测试类也很显著区别,不必要显示结构实在角色类        SubjectNormalGamePlayer proxy = new ProxySubjectNormalPlayerImpl("cutey", "123456");        proxy.login();        proxy.upgrade();        proxy.matches();    }}

强制代理


一般代理呢是去找到一个代理对象帮打,然而强制代理呢,次要是体现在“强制”,角色类会指定一个代理,其它形式找来的代理不能帮我打,肯定要用我指定的代理才行。

Subject

和一般代理模式大部分代码一样,不同的是加了一个强制指定代理对象

public interface SubjectForceGamePlayer {       //省略登录、降级和打排位等办法        //强制指定代理对象    public SubjectForceGamePlayer getForceProxy();}

RealSubject

public class ForceGamePlayerImpl implements IForceGamePlayer {    private String name;    private String password;    private IForceGamePlayer proxy = null;      //指定须要谁来代理    public ForceGamePlayerImpl(String name, String password) {        this.name = name;        this.password = password;    }        @Override    public IForceGamePlayer getForceProxy() {        //强制指定代理类,并且只有这样能力给proxy赋值        proxy =  new ForceProxyGamePlayerImpl(this);        return proxy;    }    @Override    public void login() {        //只有不是本人指定的proxy,其它形式proxy必定是null        if(proxy != null) {            if(name.equals("imperfect") && password.equals("123456")) {                System.out.println(name + "登录胜利");            }        } else {            System.out.println("须要代理");        }    }    @Override    public void upgrade() {        if(proxy != null) {            System.out.println(name + "降级");        } else {            System.out.println("须要代理");        }    }    @Override    public void matches() {        if(proxy != null) {            System.out.println(name + "打排位赛");        } else {            System.out.println("须要代理");        }    }}

ProxySubject

public class ProxySubjectForcePlayerImpl implements SubjectForceGamePlayer {    private SubjectForceGamePlayer gamePlayer;    //接管被代理对象的指定    public ProxySubjectForcePlayerImpl(SubjectForceGamePlayer gamePlayer) {        this.gamePlayer = gamePlayer;    }    //省略登录、降级和打较量的办法    //没有代理对象,临时返回本人    @Override    public SubjectForceGamePlayer getForceProxy() {        return this;    }}

Client

public class Client {    public static void main(String[] args) {        wrongProxy1();        wrongProxy2();        correctProxy();    }    public static void correctProxy() {        SubjectForceGamePlayer player = new RealSubjectForcePlayerImpl("cutey", "123456");        //你这个代理必须是我指定的,并且强制要有        SubjectForceGamePlayer proxy = player.getForceProxy();        proxy.login();        proxy.upgrade();        proxy.matches();    }    public static void wrongProxy1() {        SubjectForceGamePlayer player = new RealSubjectForcePlayerImpl("cutey", "123456");        SubjectForceGamePlayer proxy = new ProxySubjectForcePlayerImpl(player);        proxy.login();        proxy.upgrade();        proxy.matches();    }    public static void wrongProxy2() {        SubjectForceGamePlayer player = new RealSubjectForcePlayerImpl("cutey", "123456");        player.login();        player.upgrade();        player.matches();    }}

动静代理


这个应该是代理模式中用的比拟多的,也是我感觉最须要各位小伙伴了解并且把握的。所谓动静代理是指,不必在编译器指定为谁代理,而是在运行期再取得被代理的对象并且执行代理的办法。

上面将要讲的例子是利用jdk中提供的InvocationHandler和Proxy类

SubjectRealSubject 都和一般代理模式一样

ProxySubject

咱们不晓得要给谁代理,所以要用到的是继承InvocationHandler类

public class ProxySubjectDynamicPlayerImpl implements InvocationHandler {    Class cls = null;    //要代理的类    Object obj = null;    //须要代理的对象    //指定须要代理的对象    public ProxySubjectDynamicPlayerImpl(Object obj) {        this.obj = obj;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        //调用代理对象的办法        Object result = method.invoke(this.obj, args);        if(method.getName().equalsIgnoreCase("login")) {            System.out.println("异地登陆揭示:有人登录我的账户");        }        return result;    }}

Client

public class Client {    public static void main(String[] args) {        SubjectDynamicPlayer player = new RealSubjectDynamicPlayerImpl("imperfect", "123456");        //把须要代理的信息交给handler,还记得invoke办法吗        //在invoke办法中曾经实现了被代理对象的办法        InvocationHandler handler = new ProxySubjectDynamicPlayerImpl(player);        //获取被代理类的类加载属性        ClassLoader cl = player.getClass().getClassLoader();        //获取被代理类的接口        Class[] interfaces = player.getClass().getInterfaces();        //把上述的三个信息交给Proxy创立出一个代理类        SubjectDynamicPlayer proxy = (SubjectDynamicPlayer) Proxy.newProxyInstance(cl, interfaces, handler);        proxy.login();        proxy.upgrade();        proxy.matches();    }}

在编译时咱们是齐全不晓得给谁代理,一切都是在运行时才晓得,这就是“动静”

装璜模式

装璜模式就是动静地给一个对象增加一些恩爱的职责,就减少性能来说,装璜模式比生成子类更为灵便。

无论干什么,最重要的都是取长补短,对于卖手机也是如此,必定是把卖点具体地介绍,而对于毛病能不提就不提。

Component: 定义一个对象的接口,能够给这些对象动静地增加职责

ConcreteComponent: 具体的对象

Decorator: 装璜抽象类,继承了Component,从外类来扩大Component

ConcentrateDecorator: 具体的装璜类

装璜模式UML

装璜模式

Component

public abstract class ComponentMobile {    //产品名字    private String name;    //省略get,set,tostring办法    public abstract void showDetails();    public abstract void onSale(String userName);}

Concentrate Component

public class ConcreteComponentOnePlus extends ComponentMobile {    public ConcreteComponentOnePlus(String name) {        super(name);    }    @Override    public void showDetails() {        System.out.println("处理器:骁龙888 \r\n拍照:哈苏业余模式 \r\n屏幕:2k+120hz 柔性屏 \r\n充电:65w快充");    }    @Override    public void onSale(String userName) {        System.out.println(userName + "购买了" + getName());    }}

Decorator

public abstract class Decorator extends ComponentMobile {    //把要装璜的手机拿给我    private ComponentMobile mobile;    public Decorator(String name, ComponentMobile mobile) {        super(name);        this.mobile = mobile;    }    //细节还是要展现的    //只不过怎么展现呢,子类能够加以润饰    public void showDetails() {        mobile.showDetails();    }    //手机也是要发售的    public void onSale(String name) {        mobile.onSale(name);    }}

留神,咱们手机的细节还是要展现的,不能说做的不好就不说进去,坑骗消费者。能把你认出来叫化妆,不能把你认出来叫整容,咱们讲的是装璜模式,不是整容模式。

Concrete Decorator

public class ConcreteDecoratorSystem extends Decorator {    public ConcreteDecoratorSystem(String name, ComponentMobile mobile) {        super(name, mobile);    }    //装璜零碎    public void decorateScreen() {        System.out.println("出厂装备了ColorOS,其它型号的手机也会逐渐适配");    }    @Override    public void showDetails() {        //想先介绍了零碎,再说其余参数        decorateScreen();        super.showDetails();    }}
public class ConcreteDecoratorPrice extends Decorator {    public ConcreteDecoratorPrice(String name, ComponentMobile mobile) {        super(name, mobile);    }    //颁布价格    public void decoratePrice() {        System.out.println("8 + 128:4999");        System.out.println("8 + 256: 5499");    }    @Override    public void showDetails() {        super.showDetails();        //介绍完其它的后,颁布性价比较高的价格        decoratePrice();    }}

Client

public class Client {    public static void main(String[] args) {        //手机发布会,原产品        ComponentMobile mobile = new ConcreteComponentOnePlus("OnePlus 9 Pro");        //装璜下零碎        mobile = new ConcreteDecoratorSystem(mobile.getName(), mobile);        //装璜下价格        mobile = new ConcreteDecoratorPrice(mobile.getName(), mobile);        mobile.showDetails();        //用户一看,诶,不错不错,买了        mobile.onSale("cutey");    }}