《Head First 設計模式》:剩下的模式

正文

一、橋接模式

1、定義

橋接模式通過將實現和抽象分離開來,放在兩個不同的類層次中,從而使得它們可以獨立改變。

要點:

  • 當一個類存在兩個獨立變化的維度,而且都需要進行擴展時,可以將其中一個維度抽象化,另一個維度實現化。
  • 抽象化就是通過抽象類來實現多態,實現化則是通過介面來實現多態。
  • 橋接模式通過在抽象類中持有實現類介面,來將兩個維度「橋接」起來。

2、實現步驟

(1)創建實現化角色介面

/**
 * 實現化角色介面
 */
public interface Implementor {

    void action();
}

(2)創建具體實現化角色

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

    @Override
    public void action() {
        System.out.println("ConcreteImplementorA action");
    }
}
/**
 * 具體實現化角色B
 */
public class ConcreteImplementorB implements Implementor {

    @Override
    public void action() {
        System.out.println("ConcreteImplementorB action");
    }
}

(3)創建抽象化角色抽象類,並持有實現化角色介面

/**
 * 抽象化角色抽象類
 */
public abstract class Abstraction {

    /**
     * 實現化角色介面
     */
    Implementor implementor;
    
    public Abstraction(Implementor implementor) {
        this.implementor = implementor;
    }
    
    public abstract void action();
}

(4)創建具體抽象化角色

/**
 * 具體抽象化角色A
 */
public class ConcreteAbstractionA extends Abstraction {

    public ConcreteAbstractionA(Implementor implementor) {
        super(implementor);
    }
    
    @Override
    public void action() {
        System.out.print("ConcreteAbstractionA action --> ");
        // 調用實現化角色的方法
        implementor.action();
    }
}
/**
 * 具體抽象化角色B
 */
public class ConcreteAbstractionB extends Abstraction {

    public ConcreteAbstractionB(Implementor implementor) {
        super(implementor);
    }
    
    @Override
    public void action() {
        System.out.print("ConcreteAbstractionB action --> ");
        // 調用實現化角色的方法
        implementor.action();
    }
}

(5)組合抽象化角色與實現化角色

通過組合抽象化角色與實現化角色,來實現更多的功能。

public class Test {

    public static void main(String[] args) {
        // 實現化角色
        Implementor implementorA = new ConcreteImplementorA();
        Implementor implementorB = new ConcreteImplementorB();
        // 抽象化角色
        Abstraction abstractionAA = new ConcreteAbstractionA(implementorA);
        Abstraction abstractionAB = new ConcreteAbstractionA(implementorB);
        Abstraction abstractionBA = new ConcreteAbstractionB(implementorA);
        Abstraction abstractionBB = new ConcreteAbstractionB(implementorB);
        // 請求動作
        abstractionAA.action();
        abstractionAB.action();
        abstractionBA.action();
        abstractionBB.action();
    }
}

二、生成器模式(建造者模式)

1、定義

生成器模式封裝一個產品的構造過程,並允許按步驟構造。

要點:

  • 將一個複雜對象的創建過程封裝起來。
  • 允許對象通過多個步驟來創建,並且可以改變過程(這和只有一個步驟的工廠模式不同)。

2、實現步驟

(1)創建產品類

/**
 * 產品
 */
public class Product {

    /**
     * 產品部件1
     */
    private String part1;
    
    /**
     * 產品部件2
     */
    private String part2;
    
    /**
     * 產品部件3
     */
    private String part3;

    public String getPart1() {
        return part1;
    }

    public void setPart1(String part1) {
        this.part1 = part1;
    }

    public String getPart2() {
        return part2;
    }

    public void setPart2(String part2) {
        this.part2 = part2;
    }

    public String getPart3() {
        return part3;
    }

    public void setPart3(String part3) {
        this.part3 = part3;
    }

    @Override
    public String toString() {
        return "Product [part1=" + part1 + ", part2=" + part2 + ", part3=" + part3 + "]";
    }
}

(2)創建生成器抽象類

/**
 * 生成器抽象類
 */
public abstract class Builder {

    protected Product product = new Product();
    
    public abstract void buildPart1();
    
    public abstract void buildPart2();
    
    public abstract void buildPart3();
    
    /**
     * 獲取產品
     */
    public Product getProduct() {
        return product;
    }
}

(3)創建具體生成器

/**
 * 具體生成器
 */
public class ConcreteBuilder extends Builder {

    @Override
    public void buildPart1() {
        product.setPart1("product part 1");
    }

    @Override
    public void buildPart2() {
        product.setPart2("product part 2");        
    }

    @Override
    public void buildPart3() {
        product.setPart3("product part 3");        
    }
}

(4)使用生成器生成產品

public class Test {

    public static void main(String[] args) {
        // 生成器
        Builder builder = new ConcreteBuilder();
        // 生成產品
        builder.buildPart1();
        builder.buildPart2();
        builder.buildPart3();
        // 獲取產品
        Product product = builder.getProduct();
        System.out.println(product);
    }
}

三、責任鏈模式

1、定義

責任鏈模式為某個請求創建一個對象鏈。每個對象依序檢查此請求,並對其進行處理,或者將它傳給鏈中的下一個對象。

要點:

  • 將請求的發送者和接受者解耦。
  • 通過改變鏈內成員或調動它們的次序,允許你動態地新增或刪除責任。

2、實現步驟

(1)創建請求數據包類

/**
 * 請求數據包
 */
public class Request {

    /**
     * 級別
     */
    private int level;
    
    /**
     * 數據
     */
    private String data;
    
    public Request(int level, String data) {
        this.level = level;
        this.data = data;
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
}

(2)創建處理器抽象類

/**
 * 處理器抽象類
 */
public abstract class Handler {

    /**
     * 下一個處理器
     */
    protected Handler nextHandler;
    
    public Handler getNextHandler() {
        return nextHandler;
    }

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

    /**
     * 處理請求
     */
    protected abstract void handleRequest(Request request);
}

(3)創建具體處理器

/**
 * 具體處理器A
 */
public class ConcreteHandlerA extends Handler {

    @Override
    protected void handleRequest(Request request) {
        if (request.getLevel() <= 1) {
            System.out.println("ConcreteHandlerA is handling the request, data: " + request.getData());
        } else {
            getNextHandler().handleRequest(request);
        }
    }
}
/**
 * 具體處理器B
 */
public class ConcreteHandlerB extends Handler {

    @Override
    protected void handleRequest(Request request) {
        if (request.getLevel() <= 2) {
            System.out.println("ConcreteHandlerB is handling the request, data: " + request.getData());
        } else {
            getNextHandler().handleRequest(request);
        }
    }
}
/**
 * 具體處理器C
 */
public class ConcreteHandlerC extends Handler {

    @Override
    protected void handleRequest(Request request) {
        if (request.getLevel() <= 3) {
            System.out.println("ConcreteHandlerC is handling the request, data: " + request.getData());
        } else {
            System.out.println("No handler can handle the request...");
        }
    }
}

(4)使用處理器鏈處理請求

public class Test {

    public static void main(String[] args) {
        // 創建責任鏈(處理器鏈)
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();
        Handler handlerC = new ConcreteHandlerC();
        handlerA.setNextHandler(handlerB);
        handlerB.setNextHandler(handlerC);
        // 使用責任鏈處理請求
        handlerA.handleRequest(new Request(1, "請求1"));
        handlerA.handleRequest(new Request(2, "請求2"));
        handlerA.handleRequest(new Request(3, "請求3"));
        handlerA.handleRequest(new Request(4, "請求4"));
    }
}

四、蠅量模式(享元模式)

1、定義

蠅量模式能讓某個類的一個實例能用來提供許多「虛擬實例」。

要點:

  • 運用共享技術,減少運行時對象實例的個數,節省記憶體。
  • 當一個類有許多實例,而這些實例能被同一個方法控制時,可以使用蠅量模式。

2、實現步驟

(1)創建抽象蠅量類

/**
 * 抽象蠅量類
 */
public abstract class Flyweight {

    /**
     * 共享狀態(所有實例共有的、一致的狀態)
     */
    public String sharedState;

    /**
     * 非共享狀態(不同實例間不共有、或者不一致的狀態)
     */
    public final String unsharedState;
    
    public Flyweight(String unsharedState) {
        this.unsharedState = unsharedState;
    }
    
    public abstract void operate();
}

(2)創建具體蠅量類

/**
 * 具體蠅量類
 */
public class ConcreteFlyweight extends Flyweight {

    public ConcreteFlyweight(String unsharedState) {
        super(unsharedState);
        sharedState = "Shared State";
    }

    @Override
    public void operate() {
        System.out.println("ConcreteFlyweight is operating. [sharedState: " + sharedState + ", unsharedState: " + unsharedState + "]");
    }
}

(3)創建蠅量類工廠

/**
 * 蠅量類工廠
 */
public class FlyweightFactory {

    /**
     * 池容器
     */
    private static HashMap<String, Flyweight> pool = new HashMap<>();
    
    /**
     * 獲取蠅量類實例
     */
    public static Flyweight getFlyweight(String unsharedState) {
        // 從池中取出蠅量類實例
        Flyweight flyweight = pool.get(unsharedState);
        if (flyweight == null) {
            // 創建蠅量類實例,並放入池中
            System.out.println("Create flyweight instance, and put into the pool:" + unsharedState);
            flyweight = new ConcreteFlyweight(unsharedState);
            pool.put(unsharedState, flyweight);
        } else {
            System.out.println("Get flyweight instance from the pool:" + unsharedState);
        }
        return flyweight;
    }
}

(4)使用蠅量類工廠創建蠅量類

public class Test {

    public static void main(String[] args) {
        // 從工廠獲取蠅量類實例,並執行操作
        Flyweight flyweight1 = FlyweightFactory.getFlyweight("Unshared State A");
        flyweight1.operate();
        System.out.println();
        Flyweight flyweight2 = FlyweightFactory.getFlyweight("Unshared State B");
        flyweight2.operate();
        System.out.println();
        Flyweight flyweight3 = FlyweightFactory.getFlyweight("Unshared State A");
        flyweight3.operate();
    }
}

五、解釋器模式

1、定義

解釋器模式將每一個語法規則表示成一個類。

要點:

  • 當你需要實現一個簡單的語言時,就使用解釋器。
  • 解釋器模式的每一個語法規則對應一個表達式類,表達式包含終結符表達式和非終結符表達式。
  • 終結符表達式對應的語法規則不可再分解,因此終結符表達式的解釋方法不會調用其他表達式的解釋方法。
  • 非終結符表達式對應的語法規則可以分解為其他語法規則,因此非終結符表達式的解釋方法會調用到其他表達式的解釋方法。

2、實現步驟

(1)創建上下文環境類

/**
 * 上下文環境(運行環境)
 * 用於管理全局資訊
 */
public class Context {
    
    // TODO 處理全局資訊的相關方法
    
    /**
     * 運行
     */
    public void run(String data) {
        // 調用相關表達式的解釋方法
        Expression terminal1 = new TerminalExpression(data);
        Expression terminal2 = new TerminalExpression(data);
        Expression nonterminal = new NonterminalExpression(terminal1, terminal2);
        nonterminal.interpret(this);
    }
}

(2)創建表達式介面

/**
 * 表達式介面
 */
public interface Expression {

    /**
     * 執行解釋
     */
    public void interpret(Context context);
}

(3)創建具體表達式

/**
 * 終結符表達式
 */
public class TerminalExpression implements Expression {
    
    private String data;
    
    public TerminalExpression(String data) {
        this.data = data;
    }
    
    @Override
    public void interpret(Context context) {
        System.out.println("TerminalExpression is interpreting data: " + data);
        // TODO 進行解釋操作,終結符表達式不會調用其他表達式的解釋方法
    }
}
/**
 * 非終結符表達式
 */
public class NonterminalExpression implements Expression {

    private Expression exp1;
    private Expression exp2;
    
    public NonterminalExpression(Expression exp1, Expression exp2) {
        this.exp1 = exp1;
        this.exp2 = exp2;
    }
    
    @Override
    public void interpret(Context context) {
        System.out.println("NonterminalExpression is interpreting...");
        // 調用其他表達式的解釋方法
        exp1.interpret(context);
        exp2.interpret(context);
    }
}

(4)使用表達式解釋數據

public class Test {

    public static void main(String[] args) {
        Context context = new Context();
        context.run("I like cat");
    }
}

3、舉個栗子

創建一個解釋「二元運算程式碼」的解釋器。

程式碼格式:算術表達式; 變數賦值1; 變數賦值2。

程式碼例子:a + b; a = 1; b = 2。

(1)創建上下文環境類

/**
 * 上下文環境(運行環境)
 * 用於管理全局資訊
 */
public class Context {
    
    /**
     * 數據池
     */
    private static Map<Expression, Integer> dataPool =  new HashMap<Expression, Integer>();
    
    /**
     * 賦值
     */
    public void assign(Expression var, int value) {
        dataPool.put(var, value);
    }
    
    /**
     * 取值
     */
    public int lookup(Expression var) {
        Integer value = dataPool.get(var);
        return value == null ? 0 : value;
    }
    
    /**
     * 運行程式碼
     */
    public int run(String code) {
        return new CodeExpression(code).interpret(this);
    }
}

(2)創建抽象表達式

/**
 * 抽象表達式
 */
public abstract class Expression {

    protected String code;
    
    public Expression(String code) {
        this.code = code;
    }
    
    /**
     * 執行解釋
     */
    public abstract int interpret(Context context);
    
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        if (obj instanceof Expression) {
            return this.code.equals(((Expression) obj).code);
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        return code.hashCode();
    }
}

(3)創建解釋「二元運算程式碼」的具體表達式

/**
 * 程式碼表達式
 */
public class CodeExpression extends Expression {

    public CodeExpression(String code) {
        super(code);
    }

    @Override
    public int interpret(Context context) {
        // 程式碼格式: 算術表達式; 變數賦值1; 變數賦值2
        // 程式碼例子: a + b; a = 1; b = 2
        String[] codes = code.split("; ");
        // 算術表達式
        ArithExpression arith = new ArithExpression(codes[0]);
        // 賦值表達式
        AssignExpression assign = null;
        for (int i = 1; i < codes.length; i++) {
            assign = new AssignExpression(codes[i]);
            assign.interpret(context);
        }
        return arith.interpret(context);
    }
}
/**
 * 算術表達式
 */
public class ArithExpression extends Expression {

    public ArithExpression(String code) {
        super(code);
    }

    @Override
    public int interpret(Context context) {
        // a + b
        // 以"空格"分隔變數與運算符
        String[] codes = code.split(" ");
        // 變數表達式
        VarExpression var1 = new VarExpression(codes[0]);
        VarExpression var2 = new VarExpression(codes[2]);
        // 運算符表達式
        OperatorExpression operator = new OperatorExpression(var1, codes[1], var2);
        return operator.interpret(context);
    }
}
/**
 * 賦值表達式
 */
public class AssignExpression extends Expression {

    public AssignExpression(String code) {
        super(code);
    }

    @Override
    public int interpret(Context context) {
        // a = 1
        // 以"空格等號空格"分隔變數與數值
        String[] codes = code.split(" = ");
        // 變數表達式
        VarExpression var = new VarExpression(codes[0]);
        // 變數賦值
        context.assign(var, Integer.parseInt(codes[1]));
        return 0;
    }
}
/**
 * 變數表達式
 */
public class VarExpression extends Expression {

    public VarExpression(String code) {
        super(code);
    }

    @Override
    public int interpret(Context context) {
        return context.lookup(this);
    }
}
/**
 * 運算符表達式
 */
public class OperatorExpression extends Expression {

    Expression var1;
    Expression var2;
    
    public OperatorExpression(Expression var1, String code, Expression var2) {
        super(code);
        this.var1 = var1;
        this.var2 = var2;
    }

    @Override
    public int interpret(Context context) {
        OperatorExpression operator = null;
        switch (code) {
        case "+":
            operator = new AddExpression(var1, var2);
            break;
        case "-":
            operator = new SubExpression(var1, var2);
            break;
        default:
            throw new RuntimeException("暫不支援該運算");
        }
        return operator.interpret(context);
    }
}
/**
 * 加法表達式
 */
public class AddExpression extends OperatorExpression {

    public AddExpression(Expression var1, Expression var2) {
        super(var1, "+", var2);
    }

    @Override
    public int interpret(Context context) {
        return var1.interpret(context) + var2.interpret(context);
    }
}
/**
 * 減法表達式
 */
public class SubExpression extends OperatorExpression {

    public SubExpression(Expression var1, Expression var2) {
        super(var1, "-", var2);
    }

    @Override
    public int interpret(Context context) {
        return var1.interpret(context) - var2.interpret(context);
    }
}

(4)使用表達式解釋「二元運算程式碼」

public class Test {

    public static void main(String[] args) {
        // 上下文環境
        Context context = new Context();
        // 運行程式碼
        int result = context.run("a + b; a = 1; b = 2");
        System.out.println("結果1:" + result);
        result = context.run("a - b; a = 7; b = 2");
        System.out.println("結果2:" + result);
    }
}

六、中介者模式

1、定義

中介者模式用於集中相關對象之間複雜的溝通和控制方式。

要點:

  • 通過將對象彼此解耦,可以增加對象的復用性。
  • 每個對象都會在自己狀態改變時,告訴中介者。
  • 每個對象都會對中介者所發出的請求做出回應。

2、實現步驟

(1)創建交互對象抽象類

/**
 * 交互對象抽象類
 */
public abstract class InteractiveObject {

    protected Mediator mediator;
    
    public InteractiveObject(Mediator mediator) {
        this.mediator = mediator;
    }
    
    /**
     * 發送資訊
     */
    public abstract void send(String msg);
    
    /**
     * 接收資訊
     */
    public abstract void receive(String msg);
}

(2)創建具體交互對象

/**
 * 具體交互對象A
 */
public class ConcreteInteractiveObjectA extends InteractiveObject {

    public ConcreteInteractiveObjectA(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void send(String msg) {
        System.out.println("ConcreteInteractiveObjectA has sended message: " + msg);
        mediator.forward(this, msg);
    }

    @Override
    public void receive(String msg) {
        System.out.println("ConcreteInteractiveObjectA has received message: " + msg);
    }
}
/**
 * 具體交互對象B
 */
public class ConcreteInteractiveObjectB extends InteractiveObject {

    public ConcreteInteractiveObjectB(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void send(String msg) {
        System.out.println("ConcreteInteractiveObjectB has sended message: " + msg);
        mediator.forward(this, msg);
    }

    @Override
    public void receive(String msg) {
        System.out.println("ConcreteInteractiveObjectB has received message: " + msg);
    }
}
/**
 * 具體交互對象C
 */
public class ConcreteInteractiveObjectC extends InteractiveObject {

    public ConcreteInteractiveObjectC(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void send(String msg) {
        System.out.println("ConcreteInteractiveObjectC has sended message: " + msg);
        mediator.forward(this, msg);
    }

    @Override
    public void receive(String msg) {
        System.out.println("ConcreteInteractiveObjectC has received message: " + msg);
    }
}

(3)創建中介者抽象類

/**
 * 中介者抽象類
 */
public abstract class Mediator {
    
    /**
     * 註冊交互對象
     */
    public abstract void register(InteractiveObject obj);
    
    /**
     * 轉發資訊
     */
    public abstract void forward(InteractiveObject obj, String msg);
}

(4)創建具體中介者

/**
 * 具體中介者
 */
public class ConcreteMediator extends Mediator {

    /**
     * 交互對象集合
     */
    private List<InteractiveObject> interactiveObjs = new ArrayList<>();

    @Override
    public void register(InteractiveObject obj) {
        interactiveObjs.add(obj);
    }

    @Override
    public void forward(InteractiveObject obj, String msg) {
        for (InteractiveObject interactiveObj : interactiveObjs) {
            if (!interactiveObj.equals(obj)) {
                interactiveObj.receive(msg);
            }
        }
    }
}

(5)使用中介者管理交互對象之間的交互

public class Test {

    public static void main(String[] args) {
        // 中介者
        Mediator mediator = new ConcreteMediator();
        // 交互對象
        InteractiveObject objA = new ConcreteInteractiveObjectA(mediator);
        InteractiveObject objB = new ConcreteInteractiveObjectB(mediator);
        InteractiveObject objC = new ConcreteInteractiveObjectC(mediator);
        // 註冊交互對象到中介者
        mediator.register(objA);
        mediator.register(objB);
        mediator.register(objC);
        // 發送資訊
        objA.send("hello");
    }
}

七、備忘錄模式

1、定義

備忘錄模式通過將狀態存儲在對象外部,使得對象可以返回之前的狀態。

2、實現步驟

(1)創建備忘錄

/**
 * 備忘錄
 */
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;
    }
}

(2)創建備忘錄管理者

/**
 * 備忘錄管理者
 */
public class MementoCaretaker {

    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

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

(3)創建備忘錄發起人

/**
 * 備忘錄發起人
 */
public class MementoOriginator {

    private String state;

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
    
    /**
     * 創建備忘錄
     */
    public Memento createMemento() {
        return new Memento(state);
    }
    
    /**
     * 從備忘錄中恢復狀態
     */
    public void restoreFromMemento(Memento memento) {
        this.setState(memento.getState());
    }
}

(4)使用備忘錄存儲、恢復狀態

public class Test {

    public static void main(String[] args) {
        // 備忘錄管理者
        MementoCaretaker caretaker = new MementoCaretaker();
        // 備忘錄發起人
        MementoOriginator originator = new MementoOriginator();
        originator.setState("狀態1");
        System.out.println("初始狀態:" + originator.getState());
        // 備忘錄發起人創建備忘錄
        Memento memento = originator.createMemento();
        // 備忘錄管理者保存備忘錄
        caretaker.setMemento(memento);
        // 備忘錄發起人改變狀態
        originator.setState("狀態2");
        System.out.println("新狀態:" + originator.getState());
        // 從備忘錄管理者中取出備忘錄,並通過備忘錄恢復狀態
        originator.restoreFromMemento(caretaker.getMemento());
        System.out.println("恢復狀態:" + originator.getState());
    }
}

八、原型模式

1、定義

原型模式允許你通過複製現有的實例來創建新的實例。

要點:

  • 在 Java 中,這通常意味著使用 clone() 方法,或者反序列化。

2、實現步驟

(1)創建原型類,並實現 Cloneable 介面

/**
 * 原型類(實現Cloneable介面)
 */
public class Prototype implements Cloneable {

    public String type;
    
    public Prototype(String type) {
        this.type = type;
    }
    
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    /**
     * 實現clone方法
     */
    @Override
    public Prototype clone() {
        try {
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String toString() {
        return "Prototype [type=" + type + "]";
    }
}

(2)通過複製現有實例,來創建新的實例

public class Test {

    public static void main(String[] args) {
        Prototype prototype1 = new Prototype("A");
        System.out.println(prototype1);
        // 複製現有實例來創建新的實例
        Prototype prototype2 = prototype1.clone();
        System.out.println(prototype2);
    }
}

九、訪問者模式

1、定義

訪問者模式通過訪問數據結構(比如組合結構)中的每個元素,來對元素進行各種操作。

要點:

  • 通過將數據結構與數據操作分離,使得無需改變結構本身,就可以添加作用於結構內的元素的新的操作。

2、實現步驟

(1)創建元素介面

元素介面中定義了接受訪問者訪問的方法。

/**
 * 元素介面
 */
public interface Element {

    /**
     * 接受訪問者訪問
     */
    public void accept(Visitor visitor);
}

(2)創建具體元素

/**
 * 具體元素A
 */
public class ConcreteElementA implements Element {

    @Override
    public void accept(Visitor visitor) {
        // 具體元素接受訪問 -> 訪問者訪問具體元素
        visitor.visit(this);
    }
    
    public void operate() {
        System.out.println("  ConcreteElementA operate");
    }
}
/**
 * 具體元素B
 */
public class ConcreteElementB implements Element {

    @Override
    public void accept(Visitor visitor) {
        // 具體元素接受訪問 -> 訪問者訪問具體元素
        visitor.visit(this);
    }
    
    public void operate1() {
        System.out.println("  ConcreteElementB operate1");
    }
    
    public void operate2() {
        System.out.println("  ConcreteElementB operate2");
    }
}

(3)創建數據結構

/**
 * 數據結構
 */
public class DataStructure {

    private List<Element> elements = new ArrayList<>();
    
    public void add(Element element) {
        elements.add(element);
    }
    
    public void remove(Element element) {
        elements.remove(element);
    }
    
    /**
     * 接受訪問者訪問
     */
    public void accept(Visitor visitor) {
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

(4)創建訪問者介面

/**
 * 訪問者介面
 */
public interface Visitor {

    /**
     * 訪問具體元素A
     */
    public void visit(ConcreteElementA element);
    
    /**
     * 訪問具體元素B
     */
    public void visit(ConcreteElementB element);
}

(5)創建具體訪問者

/**
 * 具體訪問者
 */
public class ConcreteVisitor implements Visitor {

    @Override
    public void visit(ConcreteElementA element) {
        System.out.println("ConcreteVisitor visit ConcreteElementA:");
        // 訪問者操作元素
        element.operate();
    }

    @Override
    public void visit(ConcreteElementB element) {
        System.out.println("ConcreteVisitor visit ConcreteElementB:");
        // 訪問者操作元素
        element.operate1();        
        element.operate2();        
    }
}

(6)使用訪問者操作數據結構中的元素

public class Test {

    public static void main(String[] args) {
        // 數據結構
        DataStructure dataStructure = new DataStructure();
        dataStructure.add(new ConcreteElementA());
        dataStructure.add(new ConcreteElementB());
        // 訪問者
        Visitor visitor = new ConcreteVisitor();
        // 數據結構接受訪問者訪問
        dataStructure.accept(visitor);
    }
}