1. 程式人生 > >Java設計模式:生成器模式

Java設計模式:生成器模式

生成器 java

問題的提出:

有些類很容易創建對象,直接調用其構造方法,例如Student student = new Student(“1001”,”zhang”,21); 之所以容易創建,因為其類成員都是基本數據類型或者封裝類,或者字符串。但是如果對象的類成員還是對象,那麽創建這個對象還需要產生該對象成員的具體對象。

public class Unit1 {
}

技術分享

public class QuestionProduct {
    Unit1 u1;
    Unit2 u2;
    Unit3 u3;    public void createUnit1(){
        u1 = new Unit1();
    }    public void createUnit2(){
        u2 = new Unit2();
    }    public void createUnit3(){
        u3 = new Unit3();
    }    public void composite(){

    }    public static void main(String[] args) {
        QuestionProduct p = new QuestionProduct();
        p.createUnit1();
        p.createUnit2();
        p.createUnit3();
        p.composite();
    }
}

技術分享

Unit123為各java對象,main方法可以知道,只有當運行完p.composite()方法後,Product才真正的創建起來,問題來了,如果有兩類Product對象,又或許有很多類成員。又或者隨著Product產品種類的增加和減少,必須修改已有的源代碼。於是為了解決這類問題,生成器模式應運而生!

生成器模式的主要思路是:將一個復雜的構建與其表示相分離,使得同樣的構建過程可以創建不同的表示。簡單來說,不在同一類裏面創建該類的類成員,而是把類成員的創建交給另一個類,該類就叫做生成器!

public interface IBuild {    public Product create();
}

技術分享

public class BuildProduct implements IBuild {
    Product p = new Product();    public void createUnit1(){        //創建u1    }    public void createUnit2(){        //創建u2    }    public void createUnit3(){        //創建u3    }    public Product composite(){        //關聯Unit1,Unit2,Unit3
        return p;
    }    public Product create(){
        createUnit1();
        createUnit2();
        createUnit3();        return composite();
    }
}

技術分享

通過上面的代碼可以知道,如果需求分析發生變化,只需要增加或者刪除相應的生成器類BuildProduct即可,並不需要修改已有的類代碼。

在這基礎上,再定義一個調度類,是對生成器接口的IBuild的封裝。

技術分享

public class Director {    private IBuild iBuild;    public Director(IBuild iBuild){        this.iBuild = iBuild;
    }    public Product build(){        //System.out.println("test");        iBuild.createUnit1();
        iBuild.createUnit2();
        iBuild.createUnit3();        return iBuild.composite();
    }    public static void main(String[] args) {
        IBuild iBuild = new BuildProduct();
        Director director = new Director(iBuild);
        Product p = director.build();
    }
}

技術分享

這樣就構成生成器模式的一般模式了!一般分為以下三個步驟

1)定義產品類

2)定義n個生成器Build類

3)定義一個統一調度類Director類

技術分享

對於Director的理解:與常規的接口相比,生成器接口IBuild是特殊的,它是一個流程控制接口。該接口中定義的方法必須依照某種順序執行,一個都不能少。因此在程序中一個要體現出“流程”這一特點。而Director類的作用就是對“流程”的封裝類,其中的build方法決定了具體的流程控制過程。

對於上面的生成器模式,假如要生成兩種Product產品,一種需要三種過程,一種需要四種過程,那麽用上面的生成器模式(Model1)就不行了,因為它要求創建產品的過程必須相同(Interface IBuild定義好了創建的過程)。於是引起下面Model2的設計。

技術分享

Model2IBuild接口僅僅定義多態create()方法

public interface IBuild {    public Product create();
}

而在具體生成器類重寫多態create()方法,並調用多個個非多態方法,最終返回Product對象。

技術分享

public class BuildProduct implements IBuild {
    Product p = new Product();    public void createUnit1(){        //創建u1    }    public void createUnit2(){        //創建u2    }    public void createUnit3(){        //創建u3    }    public Product composite(){        //關聯Unit1,Unit2,Unit3
        return p;
    }    public Product create(){
        createUnit1();
        createUnit2();
        createUnit3();        return composite();
    }
}

技術分享

Director類

技術分享

public class Director {    private IBuild iBuild;    public Director(IBuild iBuild){        this.iBuild = iBuild;
    }    public Product build(){        return iBuild.create();
    }
}

技術分享

對代碼進行仔細分析可以發現,具體生成器多態的create()方法中包含了創建Product對象的全過程,Director類中的方法就顯得重復了。在這種設計中其實是可以省略Director類的,這就說明了在生成器模式中,抽象生成器和具體生成器是必須的。

而指揮類需要在實際問題中認真考慮,加以取舍!進一步思考,可以把IBuild定義成泛型接口,不僅僅是Product產品,也可以是其他需要生成器魔術的產品都可以從這接口派生。

除了以上兩種實現方式,還有第三種生成器功能的設計模式。

Model3:利用Product派生方法,可以實現類似生成器功能

技術分享

具體代碼如下

1.Product類

技術分享 View Code

2.生成器BuildProduct類

技術分享 View Code

3.指揮者類Director

技術分享 View Code

總而言之,對於生成器模式創建復制對象而言,主要的原則還是對象構建過程與表示相分離。這是一個總的思想,實現具體形式不是一成不變,大可以設計自己專屬的生成器模式框架。重要的是思想,而不是實現形式!

最後再說說生成器模式的應用場景,其中一個比較重要的作用就是解決同流程,異界面的手段之一。

例如在登錄下常常都會分不同的角色,比如教務系統登錄區分教師和學生。一般的應用也分為管理員以及普通用戶。不同的角色登錄後或顯示不同的頁面。下面就教學管理系統這個例子簡單說明。

技術分享 技術分享

技術分享

學生的具體信息在student表中,教師的具體信息在teacher表中。一個常用的功能是:管理員為學生和教師在login表中分配了用戶名和賬號,同時在studentteacher表中建立關鍵字user的記錄。但是其他具體信息如姓名年齡等是空的。

因此需要學生或者教師在登錄後首先完善個人信息。下面正是利用生成器模式設計“個人信息完善”的基礎代碼。

Mysql 表的簡單設計

技術分享 View Code

1)界面抽象生成器UIBuilder

技術分享

package BuildModel.Example;import javax.swing.*;/**
 * Created by lenovo on 2017/4/18. */public abstract class UIBuilder {    protected JPanel panel = new JPanel();    abstract public void addUI();                   //形成界面
    abstract public void registerMsg();             //註冊消息
    abstract public void initialData(String user);  //初始化界面數據
    public JPanel getPanel(){                       //返回界面面板對象
        return panel;
    }
}

技術分享

2)具體學生界面生成器類StudentBuilder

技術分享 View Code

3)DbProc數據庫自定義封裝類(註意測試時候strPwd要加上自己本地mysql的賬戶密碼)

技術分享 View Code

4)具體教師界面生成器TeacherBuilder(類似,這裏就不寫了)

5)流程指揮類Director

技術分享

package BuildModel.Example;import javax.swing.*;/**
 * Created by lenovo on 2017/4/18. */public class Director {    private UIBuilder builder;    public Director(UIBuilder builder){        this.builder = builder;
    }    public JPanel build(String user){
        builder.addUI();                //初始化界面
        builder.registerMsg();          //登記消息
        builder.initialData(user);      //填充賬號為user的初始界面顯示數據
        return builder.getPanel();
    }
}

技術分享

6)測試類

技術分享 View Code

當然這只是簡單的測試代碼,在實際應用中還要註意很多問題。


Java設計模式:生成器模式