设计模式之结构型模式总结

Structural Patterns

Posted by Chris on April 7, 2017

前言

本篇依然使用Java作为核心语言来总结结构型模式, 重点使用UML类图以减少来回切换代码而引起的逻辑混乱性.

代码已上传至GitOSC

适配器模式 - Adapter

适配器模式是将其他接口的功能进行转换, 本质是转调已有功能. 相对于装饰者模式, 适配器模式转换后的接口会变, 装饰者则保持同一个接口, 所以装饰者模式适合递归.

下面是将Android手机适配为假iPhone的例子

UML

Usage

/**
 * @author Zhao Junjian
 */
public class Client {
    public static void main(String[] args) {
        // 我们有一台普通的安卓手机
        final AndroidPhone androidPhone = new AndroidPhone();
        // 被奸商拿去改成iPhone骗小白
        final IPhoneAdaptor iPhone = new IPhoneAdaptor(androidPhone);
        // 视频通话时玛德黑屏
        iPhone.videoCall();
    }
}

桥接模式 - Bridge

维基上的对该模式的描述如下

Decouple an abstraction from its implementation allowing the two to vary independently.

读起来不太像人话, “从实现部分解耦出抽象部门, 使他们可以独立变化”

其实我们平常写的Service, ServiceImpl就是桥接模式. 桥接模式适合控制多种变量, 例如”中国人发短信”, “中国发邮件”, “美国人发短信”, “美国人发邮件”. 这里有两个变量”人”和”发布信息的方式”, 这样就抽象成两个Service了.

UML

Usage

/**
 * @author Zhao Junjian
 */
public class Client {
    public static void main(String[] args) {
        final MessageService messageService = new EmailMessageService();
        final UserService userService = new ChineseService(messageService);
        userService.giveBirth();
    }
}

装饰者模式 - Decorator

装饰者模式主要功能是以动态的透明的方式给对象添加职责, 如增强功能, 控制访问

下面是对MacBook添加Touch Bar并添加颜色Space Grey的例子

UML

Usage

/**
 * @author Zhao Junjian
 */
public class Client {
    public static void main(String[] args) {
        final MacBook macBook = new MacBook();
        final TouchBarDecorator greyMacBook = new TouchBarDecorator(macBook);
        final SpaceGreyDecorator touchBar = new SpaceGreyDecorator(greyMacBook);
        System.out.println(touchBar.feature());
    }
}

外观模式 - Facade

为多个组件提供一个同一的接口, 使系统更加易用.

外观模式正是体现迪米特法则, 客户端只需要外观类进行交互, 屏蔽了底层模块.

下面是Apple被夷为平地和Dell破产的例子

UML

Usage

/**
 * @author Zhao Junjian
 */
public class Client {
    public static void main(String[] args) {
        new TroubleFacade().boom();
    }
}

代理模式

此处仅介绍Java中的动态代理, 这里就直接看代码

/**
 * @author Zhao Junjian
 */
public class MacBookProxy implements InvocationHandler {
    private Laptop target;

    public Laptop getProxy(MacBook macBook) {
        this.target = macBook;
        return (Laptop) Proxy.newProxyInstance(
                macBook.getClass().getClassLoader(),
                macBook.getClass().getInterfaces(),
                this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("dynamic proxy");
        return method.invoke(target, args);
    }
}

Usage

/**
 * @author Zhao Junjian
 */
public class Client {
    public static void main(String[] args) {
        final MacBook macBook = new MacBook();
        final Laptop proxy = new MacBookProxy().getProxy(macBook);
      	// shutdown()是Laptop中的方法
        proxy.shutdown();
    }
}