Java設計模式-建造者(Builder)模式


@

最近在看Mybatis的源碼, 在閱讀解析 XML 配置文件的過程中, 發現使用到了建造者(Builder)模式。 因此, 打算重溫一下該設計模式。

由來

假設我們需要畫一個小人, 我們可能會有以下的構造函數定義:

public Person(HeadType headType, HairType hairType, HairColor hairColor, FaceType faceType, BodyType bodyType, ArmType amrType, LegType legTyype) {
}

看到這么一個構造函數, 估計我們自己以后回來看的時候都懵了, 這么多參數, 導致我們后續的維護也很麻煩。

而構造模式就可以解決此類的問題。

使用

目標是畫一個小人

1. 定義抽象 Builder

先定義抽象的PersonBuilder。 該類定義了畫小人需要的步驟, 這樣每個通過PersonBuilder產生的對象本質上就都是一樣的了, 只不過個性上可以不一樣。

abstract class PersonBuilder {
    protected Graphics graphics;

    public PersonBuilder(Graphics graphics) {
        this.graphics = graphics;
    }

    public abstract void buildHead();
    public abstract void buildBody();
    public abstract void buildArmLeft();
    public abstract void buildArmRight();
    public abstract void buildLegLeft();
    public abstract void buildLegRight();
}

2. 定義具體 Builder

在定義一個具體的實現類PersonFatBuilder。 該類繼承PersonBuilder, 並實現了抽象方法。

public class PersonFatBuilder extends PersonBuilder {
    public PersonFatBuilder(Graphics graphics) {
        super(graphics);
    }
    @Override
    public void buildHead() {
        graphics.drawOval(50, 20, 30, 30);
        graphics.drawArc(50, 30, 10, 5, 45, 135);
        graphics.drawArc(70, 30, 10, 5, 45, 135);
        graphics.drawArc(60, 35, 10, 5, 200, 135);
    }

    @Override
    public void buildBody() {
        graphics.drawRect(55, 50, 20, 50);
    }

    @Override
    public void buildArmLeft() {
        graphics.drawLine(55, 50, 40, 100);
    }

    @Override
    public void buildArmRight() {
        graphics.drawLine(75, 50, 90, 100);
    }

    @Override
    public void buildLegLeft() {
        graphics.drawLine(55, 100, 45, 150);
    }

    @Override
    public void buildLegRight() {
        graphics.drawLine(75, 100, 85, 150);
    }
}

3. 定義具體 Director

該類負責具體的建造過程, 對建成什么樣不關心。

public class PersonDirector {
    private PersonBuilder personBuilder;

    public PersonDirector(PersonBuilder personBuilder) {
        this.personBuilder = personBuilder;
    }

    public void drawPerson() {
        personBuilder.buildHead();
        personBuilder.buildBody();
        personBuilder.buildArmLeft();
        personBuilder.buildArmRight();
        personBuilder.buildLegLeft();
        personBuilder.buildLegRight();
    }
}

4. 測試

建立一個窗口,將小人畫出來。

 public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            // 創建窗口對象
            JFrame frame = new JFrame();
            frame.setVisible(true);
            frame.setTitle("畫人");
            frame.setSize(250, 300);

            // 設置窗口關閉按鈕的默認操作(點擊關閉時退出進程)
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

            // 把窗口位置設置到屏幕的中心
            frame.setLocationRelativeTo(null);
            frame.setContentPane(new JPanel(){
                @Override
                protected void paintComponent(Graphics g) {
                    super.paintComponent(g);
                    PersonThinBuilder thinBuilder = new PersonThinBuilder(g);
                    PersonDirector director = new PersonDirector(thinBuilder);
                    director.drawPerson();


                }
            });
        }
    });
}

結果如下:

瘦小人

定義

文字定義

將復雜對象的構建與它的表示分離, 使得同樣的構建過程可以創建不同的表示。

換句話解釋, 允許你創建不同種類的對象, 同時又能避免對構造函數的污染。當對象有多種類型時, 該模式非常有用。 或者在創建對象時涉及到很多的步驟。

結構圖

引用《大話設計模式》的一個圖

結構圖

抽象類Builder:為創建Product對象而抽象的接口。

繼承類ConcreateBuilder:具體的建造者, 構造和裝配各個部件。

具體產品類Product:我們需要建造的對象。

Director: 用來創建產品的, 其內部有Builder類型的成員變量。

優點

  1. Director 不需要知道 Product 的內部細節, 它只提供需要的信息給建設者, 由具體的建造者ConcreateBuilder處理從而完成產品的構造。
  2. 建造者模式將復雜的產品創建過程分散到了不同的對象中, 從而實現對產品創建過程更精確的控制, 創建過程更加清晰。
  3. 每個具體的建造者都可以創建出完整的產品對象, 而且是相互獨立的。 因此, 調用端可以通過不同的具體建造者就可以得到不同的對象。當有新的產品出現時, 不需要改變原有代碼, 只需要添加一個建造者即可。

舉例

現在如果我們想建造一個胖小人,有五官的。那我們只需要添加一個PersonFatBuilder類就可以了, 不需要改原有代碼。

public class PersonFatBuilder extends PersonBuilder {
    public PersonFatBuilder(Graphics graphics) {
        super(graphics);
    }
    @Override
    public void buildHead() {
        graphics.drawOval(50, 20, 30, 30);
        graphics.drawArc(50, 30, 10, 5, 45, 135);
        graphics.drawArc(70, 30, 10, 5, 45, 135);
        graphics.drawArc(60, 35, 10, 5, 200, 135);
    }

    @Override
    public void buildBody() {
        graphics.drawRect(55, 50, 20, 50);
    }

    @Override
    public void buildArmLeft() {
        graphics.drawLine(55, 50, 40, 100);
    }

    @Override
    public void buildArmRight() {
        graphics.drawLine(75, 50, 90, 100);
    }

    @Override
    public void buildLegLeft() {
        graphics.drawLine(55, 100, 45, 150);
    }

    @Override
    public void buildLegRight() {
        graphics.drawLine(75, 100, 85, 150);
    }
}

結果:

胖小人


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM