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的設計。
Model2:IBuild接口僅僅定義多態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表中分配了用戶名和賬號,同時在student和teacher表中建立關鍵字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設計模式:生成器模式