前言

憋在家里的第8天,今天开始进入结构型设计模式。

思维导图

结构型设计模式是从程序的结构上解决模块之间的耦合问题。

***模式

定义:为其他对象提供一种***以控制对这个对象的访问。

这个模式的几个角色分为以下:

  1. Subject:抽象主题类。
  2. RealSubject:真实主题类,客户端由Proxy来间接调用。
  3. Proxy:***类

这个模式就像你和代购的存在一样,你提出需求,由代购来帮你购买。这个句子里基本上就概括了整个***模式的全貌。客户端就是我们需求者,而真实主题就是你要找的代购帮你买,最后一个***,找谁买。
以下用代码表示静态***。

/**
 * 抽象主题类
 * 中心主题,买东西。
 */
public interface Shop {
    void buy();
}

/**
 * 真实主题类
 * 有这么一个人,可以干这件事,他就是***
 */
public class Person implements Shop {
    @Override
    public void buy() {
        System.out.println("购买");
    }
}

/**
 * ***类
 * 你要告诉自己找那个代购买
 */
public class WhoBuy implements Shop {
    private Shop shop;

    WhoBuy(Shop shop){
        this.shop = shop;
    }
    @Override
    public void buy() {
        shop.buy();
    }
}

/**
 * 客户端类
 * 就是这个想买东西的人了
 */
public class User {
    public static void main(String[] args) {
        Shop person = new Person();
        Shop purchase = new WhoBuy(person);
        purchase.buy();
    }
}

静态***,主要是为了让人更好的理解***模式。在开发中主要还是使用反射机制来完成的,也就是动态***模式。

/**
 * 动态***类
 */
public class DynamicPurchase implements InvocationHandler {
    private Object object;
    DynamicPurchase(Object object){
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(object, args);
        if(method.getName().equals("buy")){
            System.out.println("买上");
        }
        return result;
    }
}

/**
 * 客户端类
 */
public class User {
    public static void main(String[] args) {
        Shop person = new Person();
        DynamicPurchase dynamicPurchase = new DynamicPurchase(person);
        ClassLoader loader = person.getClass().getClassLoader();
        Shop purchase = (Shop) Proxy.newProxyInstance(loader, new Class[]{Shop.class}, dynamicPurchase);
        purchase.buy();
    }
}

和静态***的不同就在于***类,使用反射机制。
这种***模式的优点:

  1. 真实主题类只关注本身的业务逻辑。
  2. 真实主题类和***类实现了公共接口,不必担心主题类的修改影响***类。

装饰模式

动态地给一个对象添加一些额外的职责。

这个模式的角色有:

  1. Component:抽象组件。
  2. ConcreteComponent:组件具体实现类。
  3. Decorator:抽象装饰者,用于增加Component类的功能。
  4. ConcreteDecorator:装饰者的具体实现

人是一个慢慢学习的生物,从一开始只会咿咿呀呀,经过学习,学会了数学,英语。这个时候数学、英语,两个科目就是一种装饰了。

/**
 * 抽象组件
* 作为一个人,必然会有学习的能力。
 */
public abstract class Person {
    public abstract void learn();
}

/**
 * 组件具体实现类
 * 人一开始只会咿咿呀呀
 */
public class Me extends Person {
    @Override
    public void learn() {
        System.out.println("咿咿呀呀");
    }
}

/**
 * 抽象装饰类
 * 有一个老师教书育人
 */
public abstract class Teacher extends Person {

    private Person person;

    Teacher(Person person){
        this.person = person;
    }    
    @Override
    public void learn() {
        person.learn();
    }
}

/**
 * 装饰具体类
 * 这个老师教数学,也就教会了孩子
 */
public class MathTeacher extends Teacher {
    MathTeacher(Person person) {
        super(person);
    }

    public void teach(){
        System.out.println("学会了数学");
    }

    @Override
    public void learn() {
        super.learn();
        teach();
    }
}

// 具体使用
public class Main {
    public static void main(String[] args) {
        Person person = new Me();
        MathTeacher mathTeacher = new MathTeacher(person);
        mathTeacher.learn();
    }
}

优点:

  1. 能够动态的为对象增加功能。
  2. 装饰类和组件类互不干扰。
    缺点:
  3. 不论是装饰类,还是组件类都继承自Component,如果Component发生了改变,子类必然收到巨大的冲击。
  4. 装饰层数不宜过多,不仅影响效率,排查也比较苦难。

外观模式

要求一个子系统 的外部与内部的通信必须通过一个统一的对象进行。

这个模式的角色有:

  1. Facade:外观类
  2. Subsystem:子系统类

这里觉得之前看到的武侠的例子非常好。
一个武侠本身分为招式、内功、经脉三个系统,每次放招都是根据三个子系统的合理使用来释放。

/**
 * 三大子系统
 */
public class 经脉 {
    public void jingmai(){
        System.out.println("开启经脉");
    }
}

public class 内功 {
    public void JiuYang(){
        System.out.println("使用九阳神功");
    }

    public void QianKun(){
        System.out.println("使用乾坤大挪移");
    }
}

public class 招式 {
    public void QiShangQuan(){
        System.out.println("使用七伤拳");
    }

    public void ShengHuoLing(){
        System.out.println("使用圣火令");
    }
}

/**
 * 外观类
 * 也就是张无忌
 */
public class 张无忌 {
    private JingMai jingMai;
    private NeiGong neiGong;
    private ZhaoShi zhaoShi;

    张无忌(){
        jingMai = new JingMai();
        neiGong = new NeiGong();
        zhaoShi = new ZhaoShi();
    }

    public void QianKun(){
        jingMai.jingmai();
        neiGong.QianKun();
    }

    public void QiShang(){
        jingMai.jingmai();
        neiGong.JiuYang();
        zhaoShi.QiShangQuan();
    }
}

给外人看到的只有张无忌的出招是七伤拳,但是不知道内部的具体操作,这也就是外观类的整体展现方式了。
优点:

  1. 所有的依赖都是出现在外观类的,子系统间互不干扰。
  2. 具体实现对用户隐藏,也就是用户和子系统处于松耦合状态,同时保障了子系统的安全性。
    缺点:业务一旦出现变更,就需要直接修改外观类。

享元模式

使用共享对象有效地支持大量细粒度的对象。

该模式下的对象有

  1. Flyweight:抽象享元角色。
  2. ConcreteFlyweight:具体享元角色
  3. FlyweightFactory:享元工厂,负责对象创建和管理。

其实往简单了说就是一种缓冲池的技术。

/**
 * 享元工厂
 */
public class VipFactory {
    private static Map<String, Vip> cache = new HashMap<>(); 
    public static Vip getVip(String number){
        if(cache.containsKey(number)){
            return cache.get(number);
        }else{
            Vip vip = new Vip(number);
            cache.put(number, vip);
            return vip;
        }
    }
}

/**
 * 享元角色
 */
public class Vip implements IVip {
    private String name;
    private String number;

    Vip(String number){
        this.number = number;
    }

    @Override
    public void showVip(String number) {
        if (number.equals(number)) {
            System.out.println(name == null? "空": name);
        }
    }
}

/**
 * 享元抽象角色
 */
public interface IVip {
    void showVip(String number);
}

在享元工厂中我们显而易见的看到了由static修饰的cache变量,这就是一个缓冲,如果缓冲中存在,就从缓冲中取,不存在则创建。