天天看點

【設計模式】——23種設計模式——核心設計模式(含了解+代碼)【3】

設計模式——拜訪者模式

基本了解

拜訪者模式的本質就是,對于同一個對象而言,通路者的角色不一樣,所看到的資料就不一樣, 比如,對于員工資料而言,如果是CEO通路者角色則關注的資料跟CFO通路者角色所關注的資料是不一樣的;

基本意義

一般來講,一個對象有大量的資料組合需要會頻繁通路就會出現某些通路者與被通路組合的規律,如果能從中抽象出一個通路類型對應通路邏輯,那麼就可以提高代碼的維護性,将通路類型和通路邏輯統一維護;

定義拜訪者實作——以區分不同角色對象的通路邏輯

public interface Visitor {
    void visit(Engineer engineer);// 通路工程師類型
    void visit(Manager manager);// 通路經理類型
}

```java
public class CTOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程師: " + engineer.name + ", 代碼行數: " + engineer.getCodeLines());
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("經理: " + manager.name + ", 産品數量: " + manager.getProducts());
    }
}

```java
public class CEOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程師: " + engineer.name + ", KPI: " + engineer.kpi);
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("經理: " + manager.name + ", KPI: " + manager.kpi +
                ", 新産品數量: " + manager.getProducts());
    }
}

           

定義資料元被通路的邏輯——以區分不同資料對象的展示的内容

public abstract class Staff {

    public String name;
    public int kpi;// 員工KPI

    public Staff(String name) {
        this.name = name;
        kpi = new Random().nextInt(10);
    }
    // 核心方法,接受Visitor的通路
    public abstract void accept(Visitor visitor);
}
public class Engineer extends Staff {

    public Engineer(String name) {
        super(name);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    // 工程師一年的代碼數量
    public int getCodeLines() {
        return new Random().nextInt(10 * 10000);
    }
}
public class Manager extends Staff {

    public Manager(String name) {
        super(name);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    // 一年做的産品數量
    public int getProducts() {
        return new Random().nextInt(10);
    }
}

           

定義批量資料

public class BusinessReport {
    private List<Staff> mStaffs = new LinkedList<>();
    public BusinessReport() {
        mStaffs.add(new Manager("經理-ComponetElement"));
        mStaffs.add(new Engineer("工程師-ComponetElement"));
        mStaffs.add(new Engineer("工程師-B"));
        mStaffs.add(new Engineer("工程師-C"));
        mStaffs.add(new Manager("經理-B"));
        mStaffs.add(new Engineer("工程師-D"));
    }

    /**
     * 為通路者展示報表
     * @param visitor 公司高層,如CEO、CTO
     */
    public void showReport(Visitor visitor) {
        for (Staff staff : mStaffs) {
            staff.accept(visitor);
        }
    }
}
           

測試

public class _Test01 {
    public static void main(String[] args) {
        /**
         * @商務報表類
         * 包含了需要被通路的所有資料
         */
        BusinessReport report = new BusinessReport();
        /**
         * @角色比對
         * 傳入不同或實作不同實作的接口,能看到的資料是不一樣的
         */
        report.showReport(new CEOVisitor());
        report.showReport(new CTOVisitor());
    }
}

           
針對于拜訪者模式,顯然是一個新增了角色則需要新增一個通路者實作類,如果新增了資料對象則需要在拜訪者接口新增一行接口方法

設計模式——外觀模式(設計思想——針對元件的互動)

這個設計模式,主要是隐藏系統的内部的複雜,對外暴露使用者關注的方法,

而不是讓外部使用者一步步已經完成細節調用

;就就好你去銀行辦事,隻需要寫一個申請書就可以完成一些列複雜的大額轉賬流程,而不需要自己親自去調用銀行該做的事情,代碼也是一樣不需要自己親自調用内部函數的細節,這樣也降低了耦合度,

一些列流程處理的組合,減少細節碰撞,互相知道的越少越好

設計模式——組合模式(設計思想——針對同類差異化)

組合模式隻是父類抽共性的一種表現,常見于同一層次的資料元,但可能存在細微差異的情況,比如樹形結構資料中,如果所有樹形節點可能存在微小差異,我們一般也是抽共性看成同一個節點對待(共同一個抽象類或接口),内部自由實作不同的東西

一緻性父類

父類儲存了各個節點的一緻性
static abstract class Component {
        protected String name;
        public Component(String name) {
            this.name = name;
        }
        public abstract String operation();
        public boolean addChild(Component component) {
            throw new UnsupportedOperationException("addChild not supported!");
        }
        public boolean removeChild(Component component) {
            throw new UnsupportedOperationException("removeChild not supported!");
        }
        public Component getChild(int index) {
            throw new UnsupportedOperationException("getChild not supported!");
        }
    }
           

實作類

/**
     * @非子節點
     */
    static class Composite extends Component {
        private List<Component> mComponents;
        public Composite(String name) {
            super(name);
            this.mComponents = new ArrayList<>();
        }
        @Override

        public String operation() {
            StringBuilder builder = new StringBuilder(this.name);
            for (Component component : this.mComponents) {
                builder.append("\n");
                builder.append(component.operation());
            }
            return builder.toString();
        }
        @Override
        public boolean addChild(Component component) {
            return this.mComponents.add(component);
        }
        @Override
        public boolean removeChild(Component component) {
            return this.mComponents.remove(component);
        }
        @Override
        public Component getChild(int index) {
            return this.mComponents.get(index);
        }
    }
    /**
     * @葉子節點操作
     */
    static class Leaf extends Component {
        public Leaf(String name) {
            super(name);
        }
        @Override
        public String operation() {
            return this.name;
        }
    }
           

測試

public static void main(String[] args) {
        // 來一個根節點
        Component root = new Composite("root");
        // 來一個樹枝節點
        Component branchA = new Composite("---branchA");
        Component branchB = new Composite("------branchB");
        // 來一個葉子節點
        Component leafA = new Leaf("------leafA");
        Component leafB = new Leaf("---------leafB");
        Component leafC = new Leaf("---leafC");

        root.addChild(branchA);
        root.addChild(leafC);
        branchA.addChild(leafA);
        branchA.addChild(branchB);
        branchB.addChild(leafB);

        String result = root.operation();
        System.out.println(result);
}
           

設計模式——狀态模式

基本意義

類的行為是基于它的狀态改變的

最簡單的狀态模式

給定幾個if else 然後做狀态判斷改變行為模式
public class _Test01 {
    static public class Hero {
        public static final int COMMON = 1;//正常狀态
        public static final int SPEED_UP = 2;//加速狀态
        public static final int SPEED_DOWN = 3;//減速狀态
        public static final int SWIM = 4;//眩暈狀态
        private int state = COMMON;//預設是正常狀态
        public void setState(int state) {
            this.state = state;
        }
        public void run() {
            new Thread(){
                public void run(){
                    try {
                        while (true){
                            if (state == SPEED_UP) {
                                System.out.println("--------------加速跑動---------------");
                            }else if (state == SPEED_DOWN) {
                                System.out.println("--------------減速跑動---------------");
                            }else if (state == SWIM) {
                                System.out.println("--------------不能跑動---------------");
                            }else {
                                System.out.println("--------------正常跑動---------------");
                            }
                            Thread.sleep(500);
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }.start();
        }

    }

    public static void main(String[] args)  throws Exception {
        Hero hero=new Hero();
        hero.run();
        hero.setState(Hero.SPEED_UP);
        Thread.sleep(2000);
        hero.setState(Hero.SPEED_DOWN);
        Thread.sleep(2000);
        hero.setState(Hero.SWIM);
        hero.setState(Hero.COMMON);

    }
}
           

狀态模式——實作類方法

顯然利用單值做狀态判斷不利于擴充,是以利用狀态對象來實作狀态行為是可取之舉
public class StateContext {
    public static final RunState COMMON = new CommonState();
    public static final RunState SPEED_UP =  new SpeedUpState();
    public static final RunState SPEED_DOWN = new SpeedDownState();
    public static final RunState SWIM = new SwimState();//眩暈狀态
    public static interface RunState {
        void run(Hero hero);
    }
    public static class CommonState implements RunState{
        public void run(Hero hero) {
            System.out.println("--------------正常跑動---------------");
        }
    }
    public static class SpeedUpState  implements RunState{

        public void run(Hero hero) {
            System.out.println("--------------加速跑動---------------");
        }
    }
    public static class SpeedDownState  implements RunState{

        public void run(Hero hero) {
            System.out.println("--------------減速跑動---------------");
        }
    }
    public static class SwimState   implements RunState {
        public void run(Hero hero) {
            System.out.println("--------------正常跑動---------------");
        }
    }
}
           
public class Hero {
    StateContext.RunState state=new StateContext.CommonState();

    public void run() {
        Hero hero=this;
        new Thread(){
            public void run(){
                try {
                    while (true){
                        state.run(hero);
                        Thread.sleep(500);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }.start();
    }

    public void setState(StateContext.RunState state){
        this.state=state;
    }
}
           
public class _Test02 {
public static void main(String[] args)  throws Exception {
        Hero hero=new Hero();
        hero.run();`在這裡插入代碼片`
        hero.setState(StateContext.SPEED_UP);
        Thread.sleep(2000);
        hero.setState(StateContext.SPEED_DOWN);
        Thread.sleep(2000);
        hero.setState(StateContext.SWIM);

    }
}

           

狀态模式——枚舉方法

顯然過多的實作類也不好看,是以利用枚舉處理函數是最直接的,又比哈希還好,固定情況下枚舉比哈希好
public  interface  RunState {
    void run(Hero hero);
}
           

統一集中維護處理函數,比那種太多實作類好很多

public enum  StateEnum {
    COMMON("COMMON", "正常速度", new RunState() {
        public void run(Hero hero) {
            System.out.println("--------------正常跑動---------------");
        }
    }),
    SPEED_UP("SPEED_UP","加速", new RunState() {
        public void run(Hero hero) {
            System.out.println("--------------加速跑動---------------");
        }
    }),
    SPEED_DOWN("SPEED_DOWN","減速", new RunState() {
        public void run(Hero hero) {
            System.out.println("--------------減速跑動---------------");
        }
    }),
    SWIM("SWIM","眩暈", new RunState() {
        public void run(Hero hero) {
                System.out.println("--------------正常跑動---------------");
        }
    });
    private final String key;
    private final String value;
    private final RunState function;

    public String getKey() {
        return key;
    }
    public String getValue() {
        return value;
    }
    public void run(Hero hero){
        function.run(hero);
    }
    StateEnum(String key, String value,RunState function) {
        this.key = key;
        this.value = value;
        this.function=function;
    }
}

           
public class Hero {
    StateEnum state=StateEnum.COMMON;
    public void run() {
     Hero hero=this;
        new Thread(){
            public void run(){
                try {
                    while (true){
                        state.run(hero);
                        Thread.sleep(500);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }.start();
    }

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

           
public class _Test03 {
    public static void main(String[] args)  throws Exception {
        Hero hero=new Hero();
        hero.run();
        hero.setState(StateEnum.COMMON);
        Thread.sleep(2000);
        hero.setState(StateEnum.SPEED_DOWN);
        Thread.sleep(2000);
        hero.setState(StateEnum.SWIM);
    }
}
           

設計模式——中介者模式

中介者模式是用來降低多個對象和類之間的通信複雜性。這種模式提供了一個中介類,這個類就來處理不同類之間的通訊

簡單中介者

這個隻能解決統一用一個中介工具類去管理函數
public class User {
    private String name;
    public String getName() {
        return name;
    }

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

    public User (String name) {
        this.name = name;
    }

    public void sendMessage (String message) {
        StudyGroup.showMessage(this, message);
    }
}
public class StudyGroup {
    public static void showMessage (User user, String message) {
        System.out.println(new Date().toString() + " [" + user.getName() + "] :" + message);
    }
}
public class Test {
    public static void main(String[] args) {
        User ko = new User("K.O");
        User tom = new User("Tom");
        ko.sendMessage("learn design pattern.");
        tom.sendMessage("ok!");
    }
}
           

複雜中介者

中介者管理了利用哈希結構管轄指定元素引用存儲,所有外部對象與某個元件通訊必須指定key把自己傳過來

所有元件為了實作規範的通訊必須統一實作通訊接口,規範外部調用方法以及内部封裝的MetaData制定好

通訊範式接口/與中介者處理接口

/* 
   規範元件之間通訊範式
 */
@Data
public abstract  class ComponetElement {
    protected ReportMediator mediator;
    protected ComponetMetaData componetMetaData;

    public abstract void receive(ComponetElement componetElement);//接受消息
    public abstract void send(String key);//發送消息
    public void setMediator(ReportMediator mediator) {
        this.mediator = mediator;
    }
}
/* 
   規範中介者的接口邏輯
 */
public abstract class Mediator {
    protected Map<String,ComponetElement> elementMap=new ConcurrentHashMap<>();
    abstract void register(String key,ComponetElement colleague);
    abstract void relay(String key,ComponetElement colleague);
}
/* 
   每個元件的核心資料
 */
@Data
public   class ComponetMetaData {
   String serviceName;
}
           

中介者實作類

public class ReportMediator  extends Mediator{
    @Override
    void register(String key,ComponetElement colleague) {
       elementMap.put(key,colleague);
        colleague.setMediator(this);
    }
    @Override
    void relay(String key,ComponetElement colleague) {
        ComponetElement componetElement = elementMap.get(key);
        if(componetElement!=null){
            componetElement.receive(colleague);
        };
    }
}

           

元件對象實作類

public class ServiceOneComponet extends ComponetElement {
    public ServiceOneComponet(){
        this.componetMetaData=new ComponetMetaData();
        this.componetMetaData.setServiceName("ServiceOneComponet");
    }
    @Override
    public void receive(ComponetElement componetElement) {
        System.out.println(this.getComponetMetaData().getServiceName()+"接受到了"+componetElement.getComponetMetaData().getServiceName()+"的通訊");
    }
    public void send(String key) {
        super.mediator.relay(key,this);
    }
}
           
public class ServiceTwoComponet extends ComponetElement {

    public ServiceTwoComponet(){
        this.componetMetaData=new ComponetMetaData();
        this.componetMetaData.setServiceName("ServiceTwoComponet");
    }
    @Override
    public void receive(ComponetElement componetElement) {
        System.out.println(this.getComponetMetaData().getServiceName()+"接受到了"+componetElement.getComponetMetaData().getServiceName()+"的通訊");

    }
    public void send(String key) {
        super.mediator.relay(key,this);
    }
}
           
public class ServiceThreeComponet extends ComponetElement {
    public ServiceThreeComponet(){
        this.componetMetaData=new ComponetMetaData();
        this.componetMetaData.setServiceName("ServiceThreeComponet");
    }
    @Override
    public void receive(ComponetElement componetElement) {
        System.out.println(this.getComponetMetaData().getServiceName()+"接受到了"+componetElement.getComponetMetaData().getServiceName()+"的通訊");
    }

    public void send(String key) {
        super.mediator.relay(key, this);
    }
}
           

測試

public class _Test01 {
    private final  static String SERVER_COMPONET_ONE="SERVER_COMPONET_ONE";
    private final  static String SERVER_COMPONET_TWO="SERVER_COMPONET_TWO";
    private final  static String SERVER_COMPONET_THREE="SERVER_COMPONET_THREE";
    public static void main(String[] args) {
        ReportMediator reportMediator =new ReportMediator();
        ServiceOneComponet serviceOneComponetOne = new ServiceOneComponet();
        ServiceOneComponet serviceOneComponetTwo = new ServiceOneComponet();
        ServiceOneComponet serviceOneComponetThree = new ServiceOneComponet();
        reportMediator.register(SERVER_COMPONET_ONE,serviceOneComponetOne);
        reportMediator.register(SERVER_COMPONET_TWO,serviceOneComponetTwo);
        reportMediator.register(SERVER_COMPONET_THREE,serviceOneComponetThree);
        /*
         這段代碼一般都在類内部調用自動完成通訊,基于外觀模式在内部完成,但我們為了友善就在外部調用了
          */
        serviceOneComponetOne.send(SERVER_COMPONET_THREE);
    }
}

           
這種中介者模式缺點也顯而易見,就是根本無法清除究竟有多少個元件是被管理的,究竟一個元件會和多少元件完成通訊,如果為了實作更大類的差異化,則可能需要定義更通用的通路規則

設計模式——備忘錄模式

設計模式——空對象模式

設計模式——原型工廠模式

設計模式——代理模式

設計模式——解釋器模式