問題的提出:java
有些類很容易建立對象,直接調用其構造方法,例如Student student = new Student(「1001」,」zhang」,21); 之因此容易建立,由於其類成員都是基本數據類型或者封裝類,或者字符串。可是若是對象的類成員仍是對象,那麼建立這個對象還須要產生該對象成員的具體對象。mysql
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產品種類的增長和減小,必須修改已有的源代碼。因而爲了解決這類問題,生成器模式應運而生!sql
生成器模式的主要思路是:將一個複雜的構建與其表示相分離,使得一樣的構建過程能夠建立不一樣的表示。簡單來講,不在同一類裏面建立該類的類成員,而是把類成員的建立交給另外一個類,該類就叫作生成器!數據庫
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(); } }
這樣就構成生成器模式的通常模式了!通常分爲如下三個步驟ide
1)定義產品類測試
2)定義n個生成器Build類ui
3)定義一個統一調度類Director類this
對於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
固然這只是簡單的測試代碼,在實際應用中還要注意不少問題。