設計模式之禪讀書筆記-22個設計模式

最近在讀秦小波的《設計模式之禪》。本文又是一篇長達2000行的又水又長的筆記,記錄書中所講23個設計模式中的22個,基本上是將書中講的各個設計模式的定義、優勢、缺點、適用場景、demo抄下來了。推薦去閱讀原書,這是一位學識豐富且有一個有趣的靈魂的做者所寫,原書中每一個設計模式的講解都有一個十分有趣的例子,藉助這些例子能夠很好的加深理解和記憶。
設計模式感受都是相通的,以前看過一本《JavaScript設計模式與開發實踐》,其實都是講的一回事,只是由於語言特性緣由在實現方面有所區別,這本書的做者也有一個有趣的靈魂,我如今都還記得代理模式中「小明追美眉」的故事,也推薦閱讀。java

大雄和你一塊兒學編程

01單例模式

定義:算法

確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例spring

示例:編程

public class Singleton {
    private static Singleton singleton = new Singleton();

    // 私有化構造
    private Singleton() {

    }

    // 獲取實例
    public static Singleton getInstance() {
        return singleton;
    }

    // 類中其餘方法儘可能是static的
    public static void otherMethod() {

    }
}

優勢:設計模式

  1. 單例模式只生成一個實例,因此減小了系統的性能開銷
  2. 單例模式能夠避免對資源的多重佔用
  3. 在內存中,避免對同一資源佔用

缺點:安全

  1. 通常沒有接口,擴展困難
  2. 對測試不利
  3. 與單一職責原則違背

適用場景:數據結構

  1. 要求生成惟一序列號環境
  2. 建立一個對象須要消耗的資源過多
  3. 須要定義大量的靜態常量和靜態方法(如工具類)的環境

02工廠方法模式

定義:框架

定義一個用於建立對象的接口,讓子類決定實例化哪個類。工廠方法使一個類的實例化延遲到其子類dom

示例:ide

/**
 * 抽象產品
 */
public abstract class Product {
    public void method1() {
        System.out.println("method1");
    }
    abstract public void method2();
}

/**
 * 具體的一個產品
 */
public class ProductA extends Product {
    public void method2() {
        System.out.println("productA method2");
    }
}

/**
 * 具體的一個產品
 */
public class ProductB extends Product {
    public void method2() {
        System.out.println("productB method2");
    }
}

/**
 * 抽象工廠
 */
public abstract class Factory {
    public abstract <T extends Product> T createProduct(Class<T> clazz);
}

/**
 * 具體工廠
 */
public class ProductFactory1 extends Factory {
    public <T extends Product> T createProduct(Class<T> clazz) {
        Product product = null;
        try {
            product = (Product) Class.forName(clazz.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return (T) product;
    }
}

/**
 * 測試類
 */
public class FactoryTest {
    @Test
    public void test() {
        Factory factory = new ProductFactory1();
        ProductA productA = factory.createProduct(ProductA.class);
        ProductB productB = factory.createProduct(ProductB.class);
        productA.method2();
        productB.method2();
    }
}

優勢:

  1. 良好的封裝性,代碼結構清晰
  2. 工廠方法模式的擴展性很是優秀,能夠很方便的增長產品類
  3. 屏蔽產品類。只須要關心產品的接口,無需關心實現
  4. 工廠方法模式是典型的解耦框架

使用場景:

  1. 工廠方法模式是new一個對象的替代品,可是須要考慮是否須要使用工廠增長代碼複雜度
  2. 須要靈活的、可擴展的框架時,能夠考慮採用工廠方法模式
  3. 工廠方法模式能夠用在異構項目中
  4. 可使用在測試驅動開發的框架下

工廠模式擴展:

  1. 使用靜態工廠
/**
 * 靜態工廠
 */
public class ProductFactory2 {
    private ProductFactory2() {
    }

    static Product createProduct(Class<Product> clazz) {
        Product product = null;
        try {
            product = (Product) Class.forName(clazz.getName()).newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return product;
    }
}
  1. 多工廠模式

  2. 實現單例模式

  3. 延遲初始化

03抽象工廠模式

定義:

爲建立一組相關或相互依賴的對象提供一個接口,並且無須指定它們的具體類

示例:

public class Factory {
    public ProductA createProductA() {
        return new ProductA();
    }

    public ProductB createProductB() {
        return new ProductB();
    }
}

優勢:

  1. 封裝性, 只要知道工廠類是誰就能建立出對象
  2. 產品族內的約束爲非公開狀態。具體是用哪一個產品類建立的是非公開的

缺點:

  1. 難以加產品,沒加一個產品都須要改工廠

適用場景:

一個對象族(或是一組沒有任何關係的對象)都有相同的約束,則可使用抽象工廠模式。就是一堆類有相同的父類

04模板方法模式

定義:

定義一個操做中的算法的框架,而將一些步驟延遲到子類中。使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟

示例:

/**
 * 模板類
 */
public abstract class TemplateClass {
    protected abstract void method1();
    protected abstract void method2();

    /**
     * 模板方法
     */
    public void templateMethod() {
        method1();
        method2();
    }
}

/**
 * 根據模板類建立的類
 */
public class TemplateSubClass1 extends TemplateClass {
    protected void method1() {
        System.out.println("1 method1");
    }

    protected void method2() {
        System.out.println("1 method2");
    }
}

/**
 * 根據模板類建立的類
 */
public class TemplateSubClass2 extends TemplateClass {
    protected void method1() {
        System.out.println("2 method1");
    }

    protected void method2() {
        System.out.println("2 method2");
    }
}

/**
 * 測試類
 */
public class TemplateTest {
    @Test
    public void test() {
        TemplateSubClass1 templateSubClass1 = new TemplateSubClass1();
        templateSubClass1.templateMethod();
        TemplateSubClass2 templateSubClass2 = new TemplateSubClass2();
        templateSubClass2.templateMethod();
    }
}

優勢:

  1. 封裝不變部分,擴展可變部分
  2. 提取公共部分代碼,便於維護
  3. 行爲由父類控制,子類實現

缺點:

子類對父類產生了影響,在複雜的項目中,會帶來代碼閱讀的難度,會讓新手難以適應

適用場景:

多個子類有公有的方法,而且邏輯基本相同

模板方法模式擴展:

能夠經過定義開關的形式,調整模板方法的執行流程

05建造者模式

定義:

將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示

示例:

public class Product {
    private String name;
    private int price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

public class ProductBuilder {
    private Product product = new Product();

    public void buildName(String name) {
        product.setName(name);
    }

    public void buildPrice(Integer price) {
        product.setPrice(price);
    }

    public Product create() {
        return product;
    }
}

優勢:

  1. 使用建造者模式可使客戶端沒必要知道產品內部組成的細節
  2. 建造者獨立,容易擴展
  3. 因爲具體的建造者是獨立的,所以能夠對建造過程逐步細化,而不對其餘的模塊產生任何影響

缺點:

  1. 若是產品之間的差別性很大,則不適合使用建造者模式,所以其使用範圍受到必定的限制
  2. 若是產品的內部變化複雜,可能會致使須要定義不少具體建造者類來實現這種變化,致使系統變得很龐大

適用場景:

  1. 相同的方法,不一樣的執行順序,產生不一樣的事件結果時,能夠採用建造者模式
  2. 產品類很是複雜,或者產品類中的調用順序不一樣產生了不一樣的效能
  3. 在對象建立過程當中會使用到系統中的一些其餘對象,這些對象在產品對象的建立過程當中不易獲得時

06代理模式

定義:

爲其餘對象提供一種代理以控制對這個對象的訪問

示例:

/**
 * 被代理類接口
 */
public interface Subject {
    void doSomething();
}

/**
 * 真實被代理類
 */
public class RealSubject implements Subject {
    public void doSomething() {
        System.out.println("RealSubject doSomething");
    }
}

/**
 * 代理類
 */
public class SubjectProxy implements Subject {
    private Subject subject = null;

    public SubjectProxy() {
        this.subject = new RealSubject();
    }

    public void doSomething() {
        System.out.println("doSomething 被代理了");
        this.subject.doSomething();
    }
}

/**
 * 測試類
 */
public class SubjectProxyTest {
    @Test
    public void test() {
        SubjectProxy subjectProxy = new SubjectProxy();
        subjectProxy.doSomething();
    }
}

優勢:

  1. 職責清晰。真實類關注本身的邏輯,髒活累活交給代理類
  2. 高可擴展性。對真實類的變動,不須要動代理類

適用場景:

  1. 須要無侵入的對真實類作一些擴展,加強
  2. 指望控制對真實類的訪問

代理模式擴展:

  1. 普通代理

就是示例那個,調用方知道代理的存在(相似正向代理)

  1. 透明代理

調用方不知道代理的存在(相似反向代理)

/**
 * 真實被代理類
 */
public class RealSubject implements Subject {
    public RealSubject(Subject subject) throws ClassNotFoundException {
        // 注意這裏
        if (subject == null) {
            throw new ClassNotFoundException();
        }
    }

    public void doSomething() {
        System.out.println("RealSubject doSomething");
    }
}

/**
 * 代理類
 */
public class SubjectProxy implements Subject {
    private Subject subject = null;

    public SubjectProxy() {
        // 注意這裏
        try {
            this.subject = new RealSubject(this);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public void doSomething() {
        System.out.println("doSomething 被代理了");
        this.subject.doSomething();
    }
}

/***
 * 測試類
 */
public class ProxyTest {
    @Test
    public void test() {
        SubjectProxy subjectProxy = new SubjectProxy();
        subjectProxy.doSomething();
    }

    @Test
    public void test2() throws ClassNotFoundException {
        // 會報錯的
//        RealSubject realSubject = new RealSubject();
//        realSubject.doSomething();
    }
}
  1. 強制代理

必須經過真實角色查找到代理角色,不然你不能訪問

感受意義不是太大

  1. 動態代理

動態代理是在實現階段不用關心代理誰,而在運行階段才指定代理哪個對象

/**
 * 通知接口
 */
public interface Advice {
    public void exec();
}

/**
 * 通知類
 */
public class BeforeAdvice implements Advice {
    public void exec() {
        System.out.println("前置通知執行了");
    }
}

/**
 * 動態代理的handler
 */
public class MyInvocationHandler implements InvocationHandler {
    // 被代理對象
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 尋找JoinPoint連結點
        if (true) {
            new BeforeAdvice().exec();
        }
        // 執行被代理的方法
        return method.invoke(this.target, args);
    }
}

/**
 * 動態代理類
 */
public class SubjectDynamicProxy {
    public static Subject newInstance(Subject subject) {
        ClassLoader classLoader = subject.getClass().getClassLoader();
        Class<?>[] interfaces = subject.getClass().getInterfaces();
        InvocationHandler invocationHandler = new MyInvocationHandler(subject);
        return (Subject) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }
}

/**
 * 測試類
 */
public class ProxyTest {
    @Test
    public void test() {
        Subject subject = new RealSubject();
        Subject proxySubject = SubjectDynamicProxy.newInstance(subject);
        proxySubject.doSomething();
    }
}

使用jdk的動態代理要求被代理類必須實現一個接口,CGLIB動態代理沒有這個要求。

spring 的aop就是使用的動態代理技術實現的

07原型模式

定義:

用原型實例指定建立對象的種類,而且經過拷貝這些原型建立新的對象。即基於對象建立對象,而不是類

示例:

public class Prototype implements Cloneable {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected Prototype clone() throws CloneNotSupportedException {
        // 關鍵就是這個東西
        return (Prototype) super.clone();
    }
}

優勢:

  1. 性能優良:基於二進制流拷貝,比new性能高
  2. 逃避構造函數的約束

適用場景:

  1. 資源優化場景。類的初始化須要消耗不少資源
  2. 一個對象多個修改者的場景

注意點:

  1. 深拷貝與淺拷貝
  2. clone與final不能並存
  3. 拷貝時構造方法不會執行

08中介者模式

定義:

用一箇中介對象封裝一系列的對象交互,中介者使各對象不須要顯示地相互做用,從而使其耦合鬆散,並且能夠獨立地改變它們之間的交互

示例:

/**
 * 同事抽象類
 */
public abstract class Colleagure {
    protected Mediator mediator;

    public Colleagure(Mediator mediator) {
        this.mediator = mediator;
    }
}

/**
 * 具體同事類
 */
public class ConcreteColleagure1 extends Colleagure {
    public ConcreteColleagure1(Mediator mediator) {
        super(mediator);
    }

    public void selfMethod1() {
        System.out.println("ConcreteColleagure1 本身的業務邏輯");
    }

    public void depMethod1() {
        // 依賴其餘對象的邏輯,給中介者處理
        super.mediator.doSomething1();
    }
}

/**
 * 具體同事類
 */
public class ConcreteColleagure2 extends Colleagure {
    public ConcreteColleagure2(Mediator mediator) {
        super(mediator);
    }

    public void selfMethod1() {
        System.out.println("ConcreteColleagure2 本身的業務邏輯");
    }

    public void depMethod1() {
        // 依賴其餘對象的邏輯,給中介者處理
        super.mediator.doSomething2();
    }
}

/**
 * 抽象中介者
 */
public abstract class Mediator {
    protected ConcreteColleagure1 concreteColleagure1;
    protected ConcreteColleagure2 concreteColleagure2;

    public abstract void doSomething1();
    public abstract void doSomething2();

    public ConcreteColleagure1 getConcreteColleagure1() {
        return concreteColleagure1;
    }

    public void setConcreteColleagure1(ConcreteColleagure1 concreteColleagure1) {
        this.concreteColleagure1 = concreteColleagure1;
    }

    public ConcreteColleagure2 getConcreteColleagure2() {
        return concreteColleagure2;
    }

    public void setConcreteColleagure2(ConcreteColleagure2 concreteColleagure2) {
        this.concreteColleagure2 = concreteColleagure2;
    }
}

/**
 * 具體中介者
 */
public class ConcreteMediator extends Mediator {
    public void doSomething1() {
        super.concreteColleagure1.selfMethod1();
        super.concreteColleagure2.selfMethod1();
    }

    public void doSomething2() {
        super.concreteColleagure2.selfMethod1();
        super.concreteColleagure1.selfMethod1();
    }
}

/**
 * 測試類
 */
public class MediatorTest {
    @Test
    public void test() {
        Mediator mediator = new ConcreteMediator();
        ConcreteColleagure2 concreteColleagure2 = new ConcreteColleagure2(mediator);
        ConcreteColleagure1 concreteColleagure1 = new ConcreteColleagure1(mediator);
        mediator.setConcreteColleagure1(concreteColleagure1);
        mediator.setConcreteColleagure2(concreteColleagure2);
        concreteColleagure1.depMethod1();
        concreteColleagure2.depMethod1();
    }
}

優勢:

中介者模式的優勢就是減小類間的依賴,把原有的一對多的依賴變成了一對一的依賴,實現瞭解耦

適用場景:

  1. 機場調度中心
  2. MVC框架
  3. 媒體網關
  4. 中介服務

09命令模式

定義:

將一個請求封裝成一個對象,從而讓你使用不一樣的請求把客戶端參數化,對請求排隊或者記錄請求日誌,能夠提供命令的撤銷和恢復功能

示例:

/**
 * 抽象接收者
 */
public abstract class Recevier {
    public abstract void doSomething();
}

/**
 * 具體的接收者
 */
public class ConcreteRecevier1 extends Recevier {
    public void doSomething() {
        System.out.println("ConcreteRecevier1 業務邏輯");
    }
}

/**
 * 具體的接收者
 */
public class ConcreteRecevier2 extends Recevier {
    public void doSomething() {
        System.out.println("ConcreteRecevier2 業務邏輯");
    }
}

/**
 * 抽象命令類
 */
public abstract class Command {
    public abstract void execute();
}

/**
 * 具體命令類
 */
public class ConcreteCommand1 extends Command {

    Recevier recevier;

    public ConcreteCommand1(Recevier recevier) {
        this.recevier = recevier;
    }

    public ConcreteCommand1() {
        this(new ConcreteRecevier1());
    }

    public void execute() {
        recevier.doSomething();
    }
}

/**
 * 具體命令類
 */
public class ConcreteCommand2 extends Command {

    Recevier recevier;

    public ConcreteCommand2(Recevier recevier) {
        this.recevier = recevier;
    }

    public ConcreteCommand2() {
        this(new ConcreteRecevier2());
    }

    public void execute() {
        recevier.doSomething();
    }
}

/**
 * 調用者
 */
public class Invoker {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void action() {
        this.command.execute();
    }
}

/**
 * 測試類
 */
public class CommandTest {
    @Test
    public void test() {
        Command command = new ConcreteCommand1();
        Command command1 = new ConcreteCommand2();
        Invoker invoker = new Invoker();
        invoker.setCommand(command);
        invoker.action();
        invoker.setCommand(command1);
        invoker.action();
    }
}

優勢:

  1. 解耦:調用者和接受者之間沒有依賴關係
  2. 命令很容易擴展

缺點:

  • 命令的增長會帶來類數量的增長

10責任鏈模式

定義:

使多個對象都有機會處理請求,從而避免了請求的發送者和接受者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有對象處理它爲止

示例:

/**
 * 處理級別
 */
public enum Level {
    LEVEL1(1, "級別1"),
    LEVEL2(2, "級別2"),
    LEVEL3(3, "級別3");
    private int code;
    private String msg;

    private Level(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

/**
 * 請求封裝
 */
public class Request {
    Level level;

    public Request(Level level) {
        this.level = level;
    }

    public Level getRequestLevel() {
        return this.level;
    }
}

/**
 * 響應封裝
 */
public class Response {
    private int code;
    private String msg;

    public Response(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

/**
 * 處理請求抽象
 */
public abstract class Handler {
    private Handler nextHandler;

    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public final Response handleMessage(Request request) {
        Response response = null;
        if (this.getHandleLevel().getCode() == request.getRequestLevel().getCode()) {
            // 本身處理
            response = this.doRequest(request);
        } else {
            if (this.nextHandler != null) {
                // 交給下一我的處理
                response = this.nextHandler.handleMessage(request);
            } else {
                response = new Response(-1, "無人處理");
            }
        }
        return response;
    }

    // 獲取當前處理者可以處理的級別
    protected abstract Level getHandleLevel();

    // 處理請求
    protected abstract Response doRequest(Request request);
}

/**
 * 具體處理請求的類
 */
public class Level1Handler extends Handler {
    protected Level getHandleLevel() {
        return Level.LEVEL1;
    }

    protected Response doRequest(Request request) {
        return new Response(1, "第一個級別在Level1Handler處理了");
    }
}

public class Level2Handler extends Handler {
    protected Level getHandleLevel() {
        return Level.LEVEL2;
    }

    protected Response doRequest(Request request) {
        return new Response(1, "第2個級別在Level2Handler處理了");
    }
}

public class Level3Handler extends Handler {
    protected Level getHandleLevel() {
        return Level.LEVEL3;
    }

    protected Response doRequest(Request request) {
        return new Response(1, "第2個級別在Level3Handler處理了");
    }
}

/**
 * 測試類
 */
public class RequestChainTest {
    @Test
    public void test() {
        Level1Handler level1Handler = new Level1Handler();
        Level2Handler level2Handler = new Level2Handler();
        Level3Handler level3Handler = new Level3Handler();
        level1Handler.setNextHandler(level2Handler);
        level2Handler.setNextHandler(level3Handler);

        Response response = level1Handler.handleMessage(new Request(Level.LEVEL2));
        System.out.println(response.getCode());
        System.out.println(response.getMsg());
    }
}

優勢:

  1. 將請求和處理分開:請求者能夠不用知道是誰處理的,處理者能夠不用知道請求的全貌

11裝飾者模式

定義:

動態地給一個對象添加一些額外的職責。就增長功能來講,裝飾模式相比生成子類更爲靈活

示例:

/**
 * 被裝飾類的抽象
 */
public abstract class Component {
    public abstract void doSomething();
}

/**
 * 具體被裝飾者
 */
public class ConcreteComponent extends Component {
    public void doSomething() {
        System.out.println("被裝飾類的方法");
    }
}


/**
 * 裝飾類
 */
public class Decorator extends Component {
    private Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void doSomething() {
        this.component.doSomething();
    }

    public void newMethod() {
        System.out.println("新增一個方法");
    }
}

優勢:

  1. 裝飾類和被裝飾類能夠獨立發展,而不會相互耦合
  2. 裝飾模式是繼承關係的一個替代方案
  3. 裝飾模式能夠動態地擴展一個實現類的功能

缺點:

多層的裝飾是比較複雜的

適用場景:

  1. 須要擴展一個類

12策略模式

定義:

定義一組算法,將每一個算法都封裝起來,而且使它們之間能夠互換

示例:

/**
 * 策略接口
 */
public interface Strategy {
    void doSomething();
}

/**
 * 具體的策略
 */
public class Strategy1 implements Strategy {
    public void doSomething() {
        System.out.println("第一種策略");
    }
}

/**
 * 具體的策略
 */
public class Strategy2 implements Strategy {
    public void doSomething() {
        System.out.println("第一種策略");
    }
}

/**
 * 封裝策略
 */
public class Context {
    private Strategy strategy;

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public void execute() {
        this.strategy.doSomething();
    }
}

/**
 * 測試類
 */
public class StrategyTest {
    @Test
    public void test() {
        Context context = new Context();
        context.setStrategy(new Strategy1());
        context.execute();
    }
}

優勢:

  1. 算法能夠自由切換
  2. 避免使用多重條件判斷
  3. 擴展性良好,能夠很方便的增長一個策略

缺點:

  1. 策略類數量增多
  2. 全部的策略類都須要對外暴露

適用場景:

  1. 算法能夠自由切換場景
  2. 須要屏蔽算法規則的場景

13適配器模式

定義:

將一個類的接口變換成客戶端所期待的另外一種接口,從而使本來因接口不匹配而沒法在一塊兒工做的兩個類可以在一塊兒工做

示例:

/**
 * 目標角色
 */
public interface Target {
    void request();
}

/**
 * 源角色
 */
public class Adaptee {
    public void doAnyThing() {
        System.out.println("doAnyThing");
    }
}

/**
 * 適配器角色
 */
public class Atapter extends Adaptee implements Target {
    public void request() {
        super.doAnyThing();
    }
}

優勢:

  1. 適配器模式可讓兩個沒有任何關係的類在一塊兒運行
  2. 加了類的透明性
  3. 提升了類的複用度
  4. 靈活性很是好

適用場景:

當要改一個已經在生產中適用的類時能夠考慮

14迭代器模式

定義:

它提供一種方法訪問一個容器對象中各個元素,而又不需暴露該對象的內部細節

示例:

不少集合類都實現了Iterable接口,就是迭代器模式

優勢:

遍歷方便,隱藏內部細節

15組合模式

定義:

將對象組合成樹形結構以表示「部分-總體」的層次結構,使得用戶對單個對象和組合對象的使用具備一致性

示例:

/**
 * 抽象構件
 */
public abstract class Component {
    public void doSomething() {
        System.out.println("一些業務邏輯");
    }
}

/**
 * 樹枝
 */
public class Composite extends Component {
    /**
     * 子節點容器
     */
    private ArrayList<Component> componentArrayList = new ArrayList<Component>();

    // 加節點
    public void add(Component component) {
        this.componentArrayList.add(component);
    }

    // 刪節點
    public void remove(Component component) {
        this.componentArrayList.remove(component);
    }

    // 獲取子節點
    public ArrayList<Component> getChildren() {
        return this.componentArrayList;
    }
}

public class Leaf extends Component {
    @Override
    public void doSomething() {
        System.out.println("葉子");
        super.doSomething();
    }
}

/**
 * 測試類
 */
public class CompositeTest {
    @Test
    public void test() {
        Composite root = new Composite();
        root.doSomething();

        Composite branch = new Composite();
        Leaf leaf = new Leaf();
        root.add(branch);
        branch.add(leaf);
        display(root);
    }

    private void display(Composite root) {
        for (Component component1 : root.getChildren()) {
            if (component1 instanceof Leaf) {
                component1.doSomething();
            } else {
                display((Composite) component1);
            }
        }
    }
}

優勢:

  1. 高層模塊調用簡單
  2. 節點自由增長

適用場景:

  • 維護和展現部分-總體關係的場景

  • 從一個總體中可以獨立出部分模塊或功能的場景

16觀察者模式

定義:

定義對象間一種一對多的依賴關係,使得每當一個對象改變狀態,則全部依賴於它的對象都會獲得通知並被自動更新

示例:

/**
 * 觀察者接口
 */
public interface Observer {
    // 更新
    void update(Object object);
}

/**
 * 具體的觀察者
 */
public class ConcreteObserver implements Observer {
    public void update(Object object) {
        System.out.println("收到了通知"+object.toString());
    }
}

/**
 * 被觀察者抽象類
 */
public abstract class Subject {

    private ArrayList<Observer> observers = new ArrayList<Observer>();

    public void addObserver(Observer observer) {
        this.observers.add(observer);
    }

    public void removeObserver(Observer observer) {
        this.observers.remove(observer);
    }

    public void notifyObservers(Object object) {
        for (Observer observer : this.observers) {
            observer.update(object);
        }
    }
}

/**
 * 具體的被觀察者
 */
public class ConcreteSubject extends Subject {
    public void doSomething() {
        super.notifyObservers("doSomething");
    }
}

/**
 * 測試類
 */
public class ObserverTest {
    @Test
    public void test() throws InterruptedException {
        Observer observer = new ConcreteObserver();
        ConcreteSubject subject = new ConcreteSubject();
        subject.addObserver(observer);
        Thread.sleep(1000);
        subject.doSomething();
    }
}

優勢:

  1. 觀察者和被觀察者之間是抽象耦合
  2. 創建一套觸發機制

缺點:

  1. 開發效率問題
  2. 運行效率問題

適用場景:

  1. 跨系統的消息交換場景
  2. 關聯行爲場景

17門面模式

定義:

要求一個子系統的外部與其內部的通訊必須經過一個統一的對象進行。門面模式提供一個高層次的接口,使得子系統更易於使用

示例:

/**
 * 子系統
 */
public class SubSystemA {
    public void doSomethingA() {
        System.out.println("doSomethingA");
    }
}

/**
 * 子系統
 */
public class SubSystemB {
    public void doSomethingB() {
        System.out.println("doSomethingB");
    }
}


/**
 * 子系統
 */
public class SubSystemC {
    public void doSomethingC() {
        System.out.println("doSomethingC");
    }
}

/**
 * 門面
 */
public class Facade {
    private SubSystemA subSystemA = new SubSystemA();
    private SubSystemB subSystemB = new SubSystemB();
    private SubSystemC subSystemC = new SubSystemC();

    public void methodA() {
        subSystemA.doSomethingA();
    }

    public void methodB() {
        subSystemB.doSomethingB();
    }

    public void methodC() {
        subSystemC.doSomethingC();
    }
}

優勢:

  1. 減小系統的相互依賴
  2. 提升了靈活性
  3. 提升了安全性

缺點:

  1. 不符合開閉原則

適用場景:

  1. 爲一個複雜的模塊或子系統提供一個供外界訪問的接口
  2. 子系統相對獨立
  3. 預防低水平人員帶來的風險擴散

18備忘錄模式

定義:

在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態。這樣之後就可將該對象恢復到原先保存的狀態

示例:

/**
 * 發起人角色
 */
public class Originator {
    private String state;   // 內部狀態

    public Originator() {
    }

    public Originator(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    // 建立備忘錄
    public Memento createMemento() {
        return new Memento(this.state);
    }

    // 恢復備忘錄
    public void restoreMemento(Memento memento) {
        this.setState(memento.getState());
    }

    public void changeState(String state) {
        this.setState(state);
    }
}

/**
 * 備忘錄
 */
public class Memento {
    private String state; // 發起人內部狀態

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

/**
 * 備忘錄管理員角色
 */
public class Caretaker {
    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}

/**
 * 測試類
 */
public class MementoTest {
    @Test
    public void test() {
        Originator originator = new Originator("1");
        System.out.println(originator.getState());
        Caretaker caretaker = new Caretaker();
        caretaker.setMemento(originator.createMemento());
        originator.changeState("3");
        System.out.println(originator.getState());
        originator.restoreMemento(caretaker.getMemento());
        System.out.println(originator.getState());
    }
}

適用場景:

  1. 須要保存和恢復數據的相關狀態場景

19訪問者模式

定義:

封裝一些做用於某種數據結構中的各元素的操做,它能夠在不改變數據結構的前提下定義做用於這些元素的新的操做

示例:

/**
 * 訪問者接口
 */
public interface IVisitor {
    void visit(ConcreteElement1 concreteElement1);
    void visit(ConcreteElement2 concreteElement2);
}

/**
 * 具體的訪問者
 */
public class Visitor implements IVisitor {
    public void visit(ConcreteElement1 concreteElement1) {
        concreteElement1.doSomething();
    }

    public void visit(ConcreteElement2 concreteElement2) {
        concreteElement2.doSomething();
    }
}

/**
 * 抽象元素
 */
public abstract class Element {
    public abstract void doSomething(); // 業務邏輯

    public abstract void accept(IVisitor visitor); // 容許誰訪問
}

/**
 * 具體元素
 */
public class ConcreteElement1 extends Element {
    public void doSomething() {
        System.out.println("element1 業務邏輯");
    }

    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
}

/**
 * 具體元素
 */
public class ConcreteElement2 extends Element {
    public void doSomething() {
        System.out.println("element2 業務邏輯");
    }

    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
}

/**
 * 結構對象
 */
public class ObjectStructure {
    public static Element createElement() {
        Random random = new Random();
        if(random.nextInt(100) < 50) {
            return new ConcreteElement1();
        } else {
            return new ConcreteElement2();
        }
    }
}

/**
 * 測試類
 */
public class VisitorTest {
    @Test
    public void test() {
        for (int i = 0; i < 10; i++) {
            Element e = ObjectStructure.createElement();
            e.accept(new Visitor());
        }
    }
}

優勢:

  1. 符合單一職責原則
  2. 可擴展性高
  3. 靈活性高

缺點:

  1. 具體元素變動比較困難
  2. 具體元素對訪問者公佈細節
  3. 違背了依賴倒置轉原則

適用場景:

業務規則要求遍歷多個不一樣的對象

20狀態模式

定義:

當一個對象內在狀態改變時容許其改變行爲,這個對象看起來像改變了其類

示例:

/**
 * 狀態抽象類
 */
public abstract class State {
    protected Context context;

    public void setContext(Context context) {
        this.context = context;
    }

    // 行爲1
    public abstract void handle1();
    // 行爲2
    public abstract void hanle2();
}

/**
 * 具體狀態
 */
public class State1 extends State {
    public void handle1() {

    }

    public void hanle2() {
        super.context.setCurrentState(Context.STATE2);
        System.out.println("在狀態1能夠執行 handle2");
    }
}

/**
 * 具體狀態
 */
public class State2 extends State {
    public void handle1() {
        super.context.setCurrentState(Context.STATE1);
        System.out.println("在狀態2能夠執行 handle1");
    }

    public void hanle2() {

    }
}

/**
 * 環境角色
 */
public class Context {
    public static final State STATE1 = new State1();
    public static final State STATE2 = new State2();

    private State currentState;

    public State getCurrentState() {
        return currentState;
    }

    public void setCurrentState(State state) {
        this.currentState = state;
        this.currentState.setContext(this);
    }

    public void handle1() {
        this.currentState.handle1();
    }

    public void handle2() {
        this.currentState.hanle2();
    }
}

/**
 * 測試類
 */
public class StateTest {
    @Test
    public void test() {
        Context context = new Context();
        context.setCurrentState(new State1());
        context.handle1();
        context.handle2();
        context.handle2();
        context.handle1();
    }
}

優勢:

  1. 結構清晰
  2. 封裝性好
  3. 遵循設計原則

缺點:

  1. 類數量比較多

適用場景:

  1. 行爲隨狀態改變而改變的場景
  2. 條件、分支判斷語句的替代者

21享元模式

定義:

使用共享對象可有效地支持大量的細粒度的對象

示例:

/**
 * 抽象享元角色
 */
public abstract class FlyWeight {
    private String intrinsic;
    protected final String extrinsic;

    public FlyWeight(String extrinsic) {
        this.extrinsic = extrinsic;
    }

    public abstract void operate(); // 業務邏輯

    public String getIntrinsic() {
        return intrinsic;
    }

    public void setIntrinsic(String intrinsic) {
        this.intrinsic = intrinsic;
    }
}

/**
 * 具體享元角色
 */
public class ConcreteFlyWeight extends FlyWeight {
    public ConcreteFlyWeight(String extrinsic) {
        super(extrinsic);
    }

    public void operate() {
        System.out.println("業務邏輯");
    }
}

/**
 * 享元對象工廠
 */
public class FlyWeightFactory {
    private static HashMap<String, FlyWeight> flyWeightHashMap = new HashMap<String, FlyWeight>();

    public static FlyWeight getFlyWeight(String extrinsic) {
        FlyWeight flyWeight = null;
        if (flyWeightHashMap.containsKey(extrinsic)) {
            flyWeight = flyWeightHashMap.get(extrinsic);
        } else {
            flyWeight = new ConcreteFlyWeight(extrinsic);
            flyWeightHashMap.put(extrinsic, flyWeight);
        }
        return flyWeight;
    }
}

優勢:

能夠大大減小應用程序建立的對象,下降程序內存的佔用,加強程序的性能

缺點:

提升了系統複雜性,須要分離出外部狀態和內部狀態

適用場景:

  • 系統中存在大量類似的對象
  • 須要緩衝池的場景

22橋樑模式

定義:

將抽象和實現解耦,使得二者能夠獨立地變化

示例:

/**
 * 實現化角色
 */
public interface Implementor {
    void doSomething();
    void doAnyThing();
}

/**
 * 具體實現化角色
 */
public class ConcreteImplementor implements Implementor{

    public void doSomething() {
        System.out.println("doSomething");
    }

    public void doAnyThing() {
        System.out.println("doAnything");
    }
}

/**
 * 抽象化角色
 */
public abstract class Abstraction {
    private Implementor implementor;

    public Abstraction(Implementor implementor) {
        this.implementor = implementor;
    }

    public void request() {
        this.implementor.doSomething();
    }

    public Implementor getImplementor() {
        return implementor;
    }
}

/**
 * 具體的抽象化角色
 */
public class ConcreteAbstraction extends Abstraction {
    public ConcreteAbstraction(Implementor implementor) {
        super(implementor);
    }

    @Override
    public void request() {
        super.request();
        super.getImplementor().doAnyThing();
    }
}

優勢:

  1. 抽象和實現分離
  2. 優秀的擴充能力
  3. 實現細節對客戶透明

適用場景:

  1. 不但願或不適用使用繼承的場景
  2. 接口或抽象類不穩定的場景
  3. 重用性要求較高的場景
相關文章
相關標籤/搜索