一、設計模式之Flyweight——打球篇
?? 周末沒事,和朋友約好去體育館(Gymnasium)打球,這個體育館(Gymnasium)提供各種球種,因為我們人多,因此選擇了羽毛球(badminton),兵乓球(pingpangball)、排球(vollyball)等球種,我們首先要填寫選球清單(playBallList),然后去器材部領球。
下面我們看看該如何實現這個過程呢?
?
1、我們首先先定義玩球(PlayBall)這樣一個接口類:
?
public interface PlayBall {
? public void playBall( String ballName);? //玩球
}
2、玩具體的球(PlayConcreteBall)是對玩球(PlayBall)接口的具體實現:
public class PlayConcreteBall implements PlayBall{
? public void playBall(String concreteBallName) {
??? System.out.println("玩"+concreteBallName+"!");
? }
}
3、定義體育館(Gymnasium)類:
public class Gymnasium {
? private Hashtable playBallList = new Hashtable();? //體育館根據我們的需要填寫的選球清單
? public PlayBall getPlayBall(Object key) {? //得到要玩的球
??? PlayBall playBall = (PlayBall) playBallList.get(key); //根據清單獲得所需的球
??? if (playBall == null) {? //清單上沒有這種球
????? playBall = new PlayConcreteBall(); //雖然清單上沒有這種球,但還想玩,那你先得到這種球,然后補清單
????? playBallList.put(key, playBall);?? //將這種球補寫進清單
??? }
??? return playBall;
? }
? public Hashtable getPlayBallList() {? //獲得選球清單
???? return playBallList;
? }
}
4、編寫測試類:
public class Test {
? public static void main(String args[]) {
??? Gymnasium gymnasium = new Gymnasium();?? //我們去的體育館
??? PlayBall badminton = gymnasium.getPlayBall( "羽毛球" );?? //想得到羽毛球
??? PlayBall pingpangball = gymnasium.getPlayBall( "兵乓球" ); //想得到兵乓球
??? PlayBall vollyball = gymnasium.getPlayBall( "排球" );??? //想得到排球
??? Hashtable selectedBallList = gymnasium.getPlayBallList(); //器材部得到選球清單
??? ((PlayBall)selectedBallList.get("羽毛球")).playBall("羽毛球"); //得到羽毛球
??? ((PlayBall)selectedBallList.get("兵乓球")).playBall("兵乓球"); //得到兵乓球
??? ((PlayBall)selectedBallList.get("排球")).playBall("排球");? //得到排球
? }
}
5、說明:
?
A:Flyweight定義:避免大量擁有相同內容的小類的開銷(如耗費內存),使大家共享一個類(元類)。
B:從本例中我們可以看到通過選球清單,我們獲得了所需的球種,因此關鍵點就是填寫好這張選球清單,其實Flyweight的重點也就在這里。
二、設計模式之Bridge——游戲篇
??? 今天從電子市場買來兩張游戲碟,一張是三國游戲(SanGuoGame),一張是CS游戲(CSGame)。玩過游戲的人可能都知道,游戲對計算機系統(ComputerSystem)是有要求的,可能一個游戲在Windows98系統下能玩,到了Windows2000系統下就不能玩了,因此為了不走冤枉路,先看看游戲要求的計算機系統(ComputerSystem)可是一個好習慣呦!
好了,閑話少敘開始我們的游戲旅程吧:
1、? 在這里,先定義計算機系統(ComputerSystem)接口類:
public interface ComputerSystem {
? public abstract void? playGame(); //玩游戲
}
2、? 再定義對計算機系統(ComputerSystem)接口的具體實現類:
A:Windows98系統
public class Windows98 implements ComputerSystem{
? public void? playGame(){
??? System.out.println("玩Windows98游戲!");
? }
}
B:Windows2000系統
public class Windows2000 implements ComputerSystem{
? public void? playGame(){
??? System.out.println("玩Windows2000游戲!");
? }
}
3、? 定義游戲(Game)類:
public abstract class? Game? {
? public abstract void play(); //玩游戲
? protected ComputerSystem getSetupSystem(String type) { //獲得要安裝的系統
??? if (type.equals("Windows98")) { //如果游戲要求必須安裝在Windows98下
????? return new Windows98(); //使用Windows98系統
??? }
??? else if (type.equals("Windows2000")) { //如果游戲要求必須安裝在Windows2000下
????? return new Windows2000(); //使用Windows2000系統
??? }
??? else {
????? return new Windows98(); //默認啟動的是Windows98系統
??? }
? }
}
4、? 定義游戲(Game)類的子類:
A:三國游戲(SanGuoGame)
public class SanGuoGame extends Game {
? private ComputerSystem computerSystem;
? public SanGuoGame(String type) {//看游戲要求安裝在那個系統上
??? computerSystem = getSetupSystem(type);//那么使用這個系統
? }
? public void play() {//玩游戲
??? computerSystem.playGame();
??? System.out.println("我正在玩三國,不要煩我!");
? }
}
B:CS游戲(CSGame)
public class CSGame extends Game {
? private ComputerSystem computerSystem;
? public CSGame(String type) { //看游戲要求安裝在那個系統上
??? computerSystem = getSetupSystem(type); //那么使用這個系統
? }
? public void play() { //玩游戲
??? computerSystem.playGame();
??? System.out.println("我正在玩CS,不要煩我!");
? }
}
5、編寫測試類:
public class Test? {
? public static void main(String[] args) {
??? Game sanguo = new SanGuoGame("Windows98"); //游戲要求Windows98
??? sanguo.play();
??? sanguo = new SanGuoGame("Windows2000");//游戲要求Windows2000
??? sanguo.play();
??? Game cs = new CSGame("Windows98"); //游戲要求Windows98
??? cs.play();
??? cs = new CSGame("Windows2000");//游戲要求Windows2000
??? cs.play();
? }
}
6、說明:
A:Bridge定義:將抽象和行為劃分開來,各自獨立,但能動態的結合。
B:從本例中我們可以看到,不同的游戲對系統的要求是不同的,三國和CS可能都需要Windows98系統,也可能需要Windows2000系統,甚至要求不相同的系統,因此處理這類問題,我們就可以用Bridge這種模式了。
????? C:這里行為是指游戲,抽象是指系統!
三、設計模式之Chain of Responsibility——項目篇
??? 最近單位接到一個軟件項目,要求在規定的時間內完成,因此我們項目組成員就開始忙活了,我們都知道機械加工是有工序(Procedure)要求的,其實我們軟件開發也是有工序(Procedure)要求的,即首先先由分析設計人員對系統進行分析設計,然后再由程序員進行編碼,最后再由測試人員對整個系統進行測試。有人可能會說,我就偏不這樣,我就要先編碼,再分析設計,當然了,你要這樣做我也沒辦法,不過你要真這么做,嘿嘿,我想你最后可要吃苦頭的,不信你就試試看。
好了,閑話少敘,我們開始吧:
?
1、我們先定義工序(Procedure)這樣一個接口類:
public interface Procedure? {
??? public abstract void nextProcedure(Procedure procedure);? //下一工序
??? public abstract void executeProcedure(String aim);? //執行工序??
}
2、定義工序(Procedure)接口的實現類:
A:分析設計工序(DesignProcedure)
public class DesignProcedure implements Procedure {
??? private Procedure nextProcedure = null;
??? private String procedureName = "Design";??? //該工序名
?
??? public void nextProcedure(Procedure procedure) { //下一工序
??????? nextProcedure = procedure;
??? }
?
??? public void executeProcedure(String currentProcedure) { //執行工序
??????? if(currentProcedure.equals(procedureName)) {//如果當前工序和該工序相符
??????????? System.out.println("進行系統分析設計");
??????? } else {
??????????? if(nextProcedure != null) { //如果當前工序和該工序不相符則轉入下一工序
??????????????? nextProcedure.executeProcedure(currentProcedure);
??????????? }
??????? }
??? }
}
B:編碼工序(CodeProcedure)
public class CodeProcedure implements Procedure {
??? private Procedure nextProcedure = null;
??? private String procedureName = "Code"; //該工序名
?
??? public void nextProcedure(Procedure procedure) { //下一工序
??????? nextProcedure = procedure;
??? }
?
??? public void executeProcedure(String currentProcedure) { //執行工序
??????? if(currentProcedure.equals(procedureName)) {//如果當前工序和該工序相符
??????????? System.out.println("進行編碼工作");
??????? } else {
??????????? if(nextProcedure != null) { //如果當前工序和該工序不相符則轉入下一工序
??????????????? nextProcedure.executeProcedure(currentProcedure);
??????????? }
??????? }
??? }
}
C:測試工序(TestProcedure)
public class TestProcedure implements Procedure {
? private Procedure nextProcedure = null;
?? private String procedureName = "Test"; //該工序名
?
?? public void nextProcedure(Procedure procedure) { //下一工序
?????? nextProcedure = procedure;
?? }
?
?? public void executeProcedure(String currentProcedure) { //執行工序
?????? if(currentProcedure.equals(procedureName)) {//如果當前工序和該工序相符
?????????? System.out.println("進行系統測試");
?????? } else {
?????????? if(nextProcedure != null) { //如果當前工序和該工序不相符則轉入下一工序
?????????????? nextProcedure.executeProcedure(currentProcedure);
?????????? }
?????? }
?? }
}
3、編寫測試類:
public class test {
? public static void main(String[] args) {
?????? DesignProcedure design = new DesignProcedure();? //分析設計工序
?????? CodeProcedure code = new CodeProcedure();? //編碼工序
?????? TestProcedure test = new TestProcedure();? //測試工序
?
?????? design.nextProcedure(code);? //定義分析設計工序的下一工序
?????? code.nextProcedure(test);?? //定義編碼工序的下一工序
?
?????? design.executeProcedure("Design"); //開始執行工序
?????? design.executeProcedure("Code");
?????? design.executeProcedure("Test");?????
?? }
4、說明:
A: Chain of Responsibility定義:Chain of Responsibility模式是用一系列類(classes)試圖處理一個請求request,這些類之間是一個松散的耦合,唯一共同點是在他們之間傳遞request.,也就是說,來了一個請求,A類先處理,如果沒有處理,就傳遞到B類處理,如果沒有處理,就傳遞到C類處理,就這樣象一個鏈條 (chain)一樣傳遞下去。
B:在本例中,分析設計工序(DesignProcedure)、編碼工序(CodeProcedure)和測試工序(TestProcedure)中的executeProcedure執行工序方法中都對當前工序和該工序進行了判斷,如果當前工序和該工序相符就執行該工序,如果當前工序和該工序不相符則轉入下一工序執行。
C:嘿嘿,其實說白了就是:是你的工作你干,不是你的工作你就不要干,順序往下傳該誰干誰干就是了。
?
四、設計模式之Mediator——聯通篇
??? 中午吃完飯沒事,我(133用戶)就和同事張三(130用戶)、李四(131用戶)一塊去高新聯通大廳(gaoxinLianTongHall)交手機費。到了高新聯通大廳(gaoxinLianTongHall),我們發現因為是中午吃飯時間大廳里只有一個工作人員,因此我們只好一個一個來辦理交費業務了,首先是張三(130用戶),然后是李四(131用戶),最后是我(133用戶)。
好了,讓我們看看這個過程如何來實現呢:
?
1、我們先定義聯通大廳(LianTongHall)這樣一個接口類:
public interface LianTongHall {
? public void identifyUserType(LianTongUser user, String type);? //判斷用戶類型
? public void getUserMoney(String type);? //獲得用戶交的錢
}
2、定義聯通大廳(LianTongHall)的具體實現類:
public class ConcreteLianTongHall implements LianTongHall {
? private User130 user130;
? private User131 user131;
? private User133 user133;
?
? public void identifyUserType(LianTongUser user, String type) {
??? if (type == "130") {
????? user130 = (User130) user; //130用戶
??? }
??? else if (type == "131") {
????? user131 = (User131) user; //131用戶
??? }
??? else if (type == "133") {
????? user133 = (User133) user; //133用戶
??? }
? }
?
? public void? getUserMoney(String type) {? //得到用戶交的錢
??? if (type == "130") {
????? user131.pleaseWait();? //131用戶請先等
????? user133.pleaseWait();? //133用戶請先等
??? }
??? else if (type == "131") {
????? user130.pleaseWait();?? //130用戶請先等
????? user133.pleaseWait();?? //133用戶請先等
??? }
??? else if (type == "133") {
????? user130.pleaseWait();? //130用戶請先等
????? user131.pleaseWait();? //131用戶請先等
??? }
? }
}
3、定義聯通用戶(LianTongUser)接口類:
public interface LianTongUser {
? public void HandInMoney();? //交錢
? public void pleaseWait();?? //等待
}
4、定義聯通用戶(LianTongUser)接口的實現類:
A:130用戶(User130)
public class User130 implements LianTongUser {
? private final String type = "130";
? private LianTongHall liantongHall;
?
? public User130(LianTongHall liantongHall) {
????? this.liantongHall = liantongHall;
????? liantongHall.identifyUserType(this, type);? //聯通大廳判斷是那種用戶
? }
? public void HandInMoney() {
????? System.out.println("130用戶正在交錢!");
????? liantongHall.getUserMoney(type);? //聯通大廳得到用戶交的錢
? }
? public void pleaseWait() {
????? System.out.println("130用戶請先等一會!");
? }
}
B:131用戶(User131)
public class User131 implements LianTongUser {
? private final String type = "131";
? private LianTongHall liantongHall;
?
? public User131(LianTongHall liantongHall) {
????? this.liantongHall = liantongHall;
????? liantongHall.identifyUserType(this, type); //聯通大廳判斷是那種用戶
? }
? public void HandInMoney() {
????? System.out.println("131用戶正在交錢!");
????? liantongHall.getUserMoney(type); //聯通大廳得到用戶交的錢
? }
?
? public void pleaseWait() {
????? System.out.println("131用戶請先等一會!");
? }
}
C:133用戶(User133)
public class User133 implements LianTongUser {
? private final String type = "133";
? private LianTongHall liantongHall;
?
? public User133(LianTongHall liantongHall) {
????? this.liantongHall = liantongHall;
????? liantongHall.identifyUserType(this, type); //聯通大廳判斷是那種用戶
? }
? public void HandInMoney() {
????? System.out.println("133用戶正在交錢!");
????? liantongHall.getUserMoney(type); //聯通大廳得到用戶交的錢
? }
?
? public void pleaseWait() {
????? System.out.println("133用戶請先等一會!");
? }
}
?
5、編寫測試類:
public class Test? {
??? public static void? main(String[] args) {
??????? LianTongHall gaoxinLianTongHall = new ConcreteLianTongHall(); //高新聯通大廳
??????? User130 zhangsan = new User130(gaoxinLianTongHall); //張三
??????? User131 lisi = new User131(gaoxinLianTongHall);?? //李四
??????? User133 me = new User133(gaoxinLianTongHall);?? //我
?
??????? zhangsan.HandInMoney();? //張三交錢
??????? lisi.HandInMoney();? //李四交錢
??????? me.HandInMoney();?? //我交錢
??? }
}
6、說明:
A:Mediator定義:用一個中介對象來封裝一系列關于對象交互行為。
B:每個成員都必須知道中介對象,并且和中介對象聯系,而不是和其他成員聯系。
C:在本例中,中介對象就相當于我們的聯通大廳,我們都是和聯通大廳發生關系,張三、李四和我之間是沒有交錢關系的。
五、設計模式之Strategy——簡歷篇
?? 表弟馬上就要大學畢業,找工作要寫簡歷(Resume),因此他就來問我關于這方面的問題。我告訴他最好寫兩種類型的簡歷,一種是用中文寫的,一種是用英文寫的,如果是國企的話,就投中文簡歷(ChineseResume),如果是外企的話,就投英文簡歷(EnglishResume),嘿嘿,原因在這里就沒必要多說了吧。
下面讓我們看看這個過程該如何實現呢?
?
1、我們先定義簡歷(Resume)接口類:
?
public interface Resume {
? public void writeText();
}
2、再定義對簡歷(Resume)接口的具體實現:
A:中文簡歷(ChineseResume)
public class ChineseResume implements Resume{
? public void writeText(){
??? System.out.println("用中文寫簡歷!");
? }
}
B:英文簡歷(EnglishResume)
public class EnglishResume implements Resume{
? public void writeText(){
??? System.out.println("用英文寫的簡歷!");
? }
}
3、定義投遞策略(Strategy)類:
public class Strategy {
? private Resume resume;
? public Strategy(Resume resume) { //使用簡歷的策略
??? this.resume=resume;
? }
? public void postResume() { //投遞簡歷
??? System.out.println("投遞");
??? resume.writeText();
? }
}
4、編寫測試類:
public class Test {
? public static void main(String args[]) {
??? //如果是國企
??? Resume brotherResume = new ChineseResume();? //表弟用中文寫的簡歷
??? Strategy strategy = new Strategy(brotherResume); //使用用中文寫的簡歷
??? strategy.postResume();? //給國企投遞該簡歷
??? //如果是私企
??? brotherResume = new EnglishResume();?? //表弟用英文寫的簡歷
??? strategy = new Strategy(brotherResume);? //使用用英文寫的簡歷
??? strategy.postResume();? //給私企投遞該簡歷
?
??
? }
}
5、說明:
A:Strategy模式主要是定義一系列的算法,把這些算法一個個封裝成單獨的類。
B:在本例中,中文簡歷(ChineseResume)和英文簡歷(EnglishResume)就相當于兩種算法,同時我們把它定義成兩個單獨的類。
C:在找工作時,我們可以根據企業類型選擇投遞那種簡歷,Strategy模式和Factory模式的不同之處是:Strategy模式主要是用來選擇不同的算法,而Factory模式的重點是用來創建對象。
六、設計模式之Observer——公交篇
??? 說到公交車,我想大家都不陌生吧,坐過公交車的朋友可能都知道,一般公交車上都有售票員(BusConductor),當然無人售票車要除外了。售票員(BusConductor)除了收取乘客(Passenger)的車費還起著監控的作用。
下面讓我們看看這個過程該如何實現呢?
?
1、我們先定義售票員(BusConductor)接口類:
?
public interface BusConductor {
? public void getCurrentPassenger(Passenger passenger);? //獲得當前乘客情況
}
2、再定義對售票員(BusConductor)接口的具體實現:
public class ConcreteBusConductor implements BusConductor{
? private Vector vectorBus;? //公交車vectorBus
? private Passenger passenger;
? public ConcreteBusConductor(Passenger passenger) {
??? this.passenger=passenger;
? }
? public void getCurrentPassenger(Passenger passenger) {
????? vectorBus = passenger.getCurrentPassenger();? //獲得當前的乘客情況
????? for(int i = 0; i < vectorBus.size(); i++) {
????????? System.out.println("公交車上有:" + (String)vectorBus.get(i));
????? }
? }
? public void findPassengerChange(String action, String str) { //公交車乘客變化
????? passenger.setCurrentPassenger(action, str);
? }
? public void observeResult() {? //觀察到的情況
????? passenger.showPassengerInfo();
? }
?
}
3、定義乘客(Passenger)接口類:
public interface Passenger {
? public abstract void attach(BusConductor busConductor);? //將乘客和售票員關聯起來
?
? public abstract void? showPassengerInfo();? //傳遞乘客情況
?
? public abstract Vector getCurrentPassenger();? //獲得當前乘客情況
?
? public abstract void? setCurrentPassenger(String act, String str);? //設置當前乘客情況
}
4、定義對乘客(Passenger)接口的具體實現:
public class ConcretePassenger implements Passenger{
? private List observerList; //觀察者列表
? private Vector vectorBus;? //公交車vectorBus
? public ConcretePassenger() {
??? observerList =? new ArrayList();
??? vectorBus = new Vector();
? }
? public void attach(BusConductor busConductor) {
????? observerList.add(busConductor);?? //將公交車售票員增加到觀察者列表
? }
?
? public void showPassengerInfo() {
????? for(int i = 0; i < observerList.size(); i++) {
????????? ((BusConductor)observerList.get(i)).getCurrentPassenger(this);? //使公交車售票員獲得當前乘客情況
????? }
? }
? public void setCurrentPassenger(String act, String str) {
????? if(act.equals("up")) {? //乘客上車
????????? vectorBus.add(str);? //將該乘客增加到公交車vectorBus中
????? } else if(act.equals("down")) {? //乘客下車
????????? vectorBus.remove(str);? //將該乘客從公交車vectorBus中刪除
????? }
? }
? public Vector getCurrentPassenger() {? //獲得當前乘客情況
????? return vectorBus;
? }
?
}
5、編寫測試類:
public class Test? {
? public static void main(String[] args) {
??? Passenger passenger = new ConcretePassenger();
??? ConcreteBusConductor busConductor = new ConcreteBusConductor(passenger);
??? passenger.attach(busConductor);? //將公交車車售票員和乘客聯系起來
?
??? //公交車售票員觀察到的情況
??? System.out.println("公交車售票員觀察到的情況:");
??? passenger.setCurrentPassenger("up", "乘客張三");? //上來乘客張三
??? passenger.setCurrentPassenger("up", "乘客李四");? //上來乘客李四??
busConductor.observeResult();
?
??? //公交車售票員觀察到的情況
??? System.out.println("公交車售票員觀察到的情況:");
??? busConductor.findPassengerChange("down", "乘客李四"); //下去乘客李四
??? busConductor.findPassengerChange("up", "乘客王五");?? //上來乘客王五
??? busConductor.observeResult();
? }
}
5、說明:
A:定義:反映對象間的的依賴關系,當一個對象的狀態發生改變時, 所有依賴于它的對象都得到通知并被自動更新。
B:在本例中,公交車售票員是觀察者,當乘客情況發生變化時,公交車售票員能及時獲得這個信息。
C:Observer用于需要及時展現信息變化的系統、比如可以用于股票、稅務上等。
七、設計模式之Singleton——生育篇
??? 老媽對我們沒給她生個小子而是個女兒始終耿耿于懷,這不最近不知從那里聽說現在政策允許再生一胎的消息后,不停的在我耳邊嘮叨。說道生孩子,就不得不提一提我國的計劃生育政策,"只生一個好,兒女都一樣","少生,優生,幸福一生"等等這些標語滿大街都是,計劃生育政策也確實為我國控制人口立下了汗馬功勞,不過我覺得讓許多人真正只想生一個的應該歸功于教育產業化,醫療產業化等等這一大群產業化,至少我就是這樣想的。嘿嘿,好象說遠了,那好,讓我們言歸正傳開始吧。
?
?
1、我們定義孩子(Child)類:
?
public class Child {
? private static Child myChild = null; //我的孩子
? private Child(){
? }
? public static Child getChild() { //生孩子
? if(myChild == null) {
??? System.out.println("你還沒有孩子,可以生一個!");
??? myChild = new Child();
? }
? else{
??? System.out.println("你已經有孩子了,不能再生了!");
? }
??? return myChild ;
?}
}
2、編寫測試類:
public class Test {
? public static void main(String args[]) {
??? Child.getChild();
??? Child.getChild();? //當你已有一個孩子而再想生一個時,會提示你不能再生了
? }
}
3、說明:
?
A:定義:Singleton模式的作用是保證在Java應用程序中,一個類Class只有一個實例存在。
B:其實本例也可以通過使用synchronized關鍵字來實現,板橋兄的文章對此闡述的很清楚,恕在此就不多說了。
?
4、特別感謝:
感謝zdr29473 、凌寒、flylyke等廣大網友的支持,現已將代碼進行了修改,希望大家多提寶貴意見,讓我們共同進步吧,再次感謝。
八、設計模式之Command——電視篇
??? 每天晚上,搶電視遙控器都是我們家的保留節目。女兒喜歡看卡通屏道,老婆喜歡看電視劇屏道,我呢則喜歡看足球屏道。因此誰控制了遙控器,就等于實現了自己的節目夢想了。嘿嘿,其實每次都是我女兒成功得到,而且她還每次都陣陣有詞的說:"大的應該讓小的嗎?",你看這孩子,不知跟誰學的。然后遙控器就是老婆的,最后才輪到我,當我高興的按到足球屏道時,播音員說:"今天的節目就到這里了,請明天在看!",我倒地狂嘔血。
大家都知道電視遙控器節目面板(ProgramPan)是由節目按鈕組成,通過選擇相應的節目按鈕,就可以切換到相應的節目屏道。
下來讓我們看看如何實現通過遙控器按鈕選擇節目屏道的過程吧。
?
1、在這里,先定義遙控器按鈕(RemoteControlButton)接口:
public interface RemoteControlButton {
? public abstract void? selectProgram(); //選擇節目屏道
}
2、再定義遙控器按鈕(RemoteControlButton)接口的實現類:
A:卡通節目按鈕(CartonProgramButton)類:
public class CartonProgramButton implements RemoteControlButton{
? public void selectProgram() {
??? System.out.println("選擇了卡通屏道!");
? }
}
B:電視劇節目按鈕(TvPlanProgramButton)類:
public class TvPlanProgramButton implements RemoteControlButton {
? public void selectProgram() {
??? System.out.println("選擇了電視劇屏道!");
? }
}
C:足球節目按鈕(FootProgramButton)類:
public class FootProgramButton implements RemoteControlButton {
? public void selectProgram() {
??? System.out.println("選擇了足球屏道!");
? }
}
3、遙控器節目面板(ProgramPan)類:用來控制節目按鈕,顯示節目
public class ProgramPan {
? public static List programList() {
??? List list = new ArrayList();? //節目屏道按鈕列表
??? list.add(new CartonProgramButton()); //卡通屏道按鈕
??? list.add(new TvPlanProgramButton()); //電視劇屏道按鈕
??? list.add(new FootProgramButton());?? //足球屏道按鈕
??? return list;
? }
}
4、編寫測試類:
public class TestCommand {
? public static void main(String[] args) {
??? List list = ProgramPan.programList();? //獲得節目屏道按鈕
??? for (Iterator it = list.iterator();it.hasNext();)
????? ( (RemoteControlButton) it.next()).selectProgram();? //選擇節目屏道中對應的節目
? }
}
5、說明:
A:Command說白了就是通過選擇一個個命令,然后執行相應動作。
B:Command是對行為進行封裝的典型模式,在本例中通過遙控器節目面板(ProgramPan)這個封裝類來實現我們看電視節目的目的。
C:Command模式和Facade(外觀)模式似乎比較相似。都是通過封裝類來進行訪問的。如何區分,對這點我也比較疑惑。
?? D:Command模式是用collection的對象容器類,把另一些類放到里面,以實現集體的一塊操作,以進行封裝。facade模式是把某個功能的操作,集中放在一起,使之用一個統一的,對外接口,比如:封裝數據庫操作,發郵件操作等等。
?? 6、特此感謝:
?? 感謝changlich網友對Command模式和facade模式的區別的解釋,特此將這個解釋加入到說明中,希望能對大家有所幫助。再次感謝大家的支持。
九、設計模式之State——交通篇
?? "小朋友過馬路,左右看,紅燈停,綠燈行,阿姨夸我是乖寶寶。",我給女兒念著兒歌,突然女兒問我,什么是紅綠燈啊?為了給她說清楚,我特意帶她看我們家附近的交通燈(NearMyFamilyTrafficLight)的運行。我們都知道,交通燈有三種狀態:紅燈(RedLight)、黃燈(YellowLight)和綠燈(GreenLight)。交通燈狀態的改變是由控制中心(ControlCenter)來控制的。
?
下面讓我們來看看這個過程是如何實現的。
1、? 在這里,先定義交通燈(TrafficLight)接口類:
public interface TrafficLight {
? public void showRedLight();? //顯示紅燈
? public void showGreenLight();//顯示綠燈
? public void showYellowLight(); //顯示黃燈
}
2、我們家附近的交通燈(NearMyFamilyTrafficLight)是對交通燈(TrafficLight)接口的具體實現:
public class NearMyFamilyTrafficLight implements TrafficLight{
? public void showRedLight(){
??? System.out.println("紅燈亮了,不能通過!");
? }
? public void showGreenLight(){
??? System.out.println("綠燈亮了,可以通過!");
? }
? public void showYellowLight(){
??? System.out.println("黃燈亮了!");
? }
?
}
3、定義控制中心(ControlCenter)類:
public class ControlCenter {
? private NearMyFamilyTrafficLight trafficLight; //我們家附近的交通燈
? public void changeState(NearMyFamilyTrafficLight trafficLight) {
????? this.trafficLight = trafficLight;
? }
? public void showRedLight() { //顯示紅燈
????? trafficLight.showRedLight();
? }
? public void showGreenLight() { //顯示綠燈
????? trafficLight.showGreenLight();
? }
? public void showYellowLight() { //顯示黃燈
????? trafficLight.showYellowLight();
? }
}
4、我們家附近的交通燈(NearMyFamilyTrafficLight)實際上有紅、黃、綠三盞燈組成:
A:紅燈(RedLight)類:
public class RedLight extends NearMyFamilyTrafficLight{
? public static boolean? existRedLight = false;
? public static RedLight getRedLight() {? //獲得紅燈
????? if(existRedLight==false) {
????????? existRedLight = true;
????????? return new RedLight();
????? }
????? return null;
? }
}
B:綠燈(GreenLight)類:
public class GreenLight extends NearMyFamilyTrafficLight{
? public static boolean? existGreenLight = false;
? public static GreenLight getGreenLight() { //獲得綠燈
????? if(existGreenLight==false) {
????????? existGreenLight = true;
????????? return new GreenLight();
????? }
????? return null;
? }
}
C:黃燈(YellowLight)類:
public class YellowLight extends NearMyFamilyTrafficLight{
? public static boolean? existYellowLight = false;
? public static YellowLight getYellowLight() { //獲得黃燈
????? if(existYellowLight==false) {
????????? existYellowLight = true;
????????? return new YellowLight();
????? }
????? return null;
? }
}
5、編寫測試類:
public class Test {
? public static void? main(String args[]){
??? ControlCenter controlCenter = new ControlCenter();?? //控制中心
??? NearMyFamilyTrafficLight redLight = RedLight.getRedLight();? //紅燈
????????? NearMyFamilyTrafficLight greenLight = GreenLight.getGreenLight(); //綠燈
????????? NearMyFamilyTrafficLight yellowLight = YellowLight.getYellowLight(); //黃燈
??? controlCenter.changeState(redLight); //改變成紅燈狀態
??? controlCenter.showRedLight();? //顯示紅燈
??? controlCenter.changeState(yellowLight); //改變成黃燈狀態
??? controlCenter.showYellowLight();? //顯示黃燈
??? controlCenter.changeState(greenLight);? //改變成綠燈狀態
??? controlCenter.showGreenLight(); //顯示綠燈
? }
}
6、說明:
A:State的定義: 不同的狀態,不同的行為;或者說,每個狀態有著相應的行為。
B:我們可以看到,燈狀態的改變是有控制中心來控制,通過顯示不同的燈,實現了交通的正常運轉。
C:因此當有狀態切換這種事情要處理時,我們就可以用State這種模式了。
十、設計模式之Proxy——買票篇
今年過年手氣好,打牌贏了100塊,我得意的笑,我得意的笑,總之一個字"爽"。因為往年打牌從沒贏過啊!我高興的回到家里,還沒等我開口報告戰況,老婆撂給我一句話"我弟要回上海,你給買張票吧。"我心里雖然不高興,但臉上卻表現出很開心的樣子,立刻用堅定語氣說到:"請領導放心,保證完成任務!"。保證歸保證,可是大過年的票也確實難買,在經過一番挫折后(嗚嗚),我只好去找票販子(Proxy)。
說到代理這個詞,大家可能都不陌生,其實現在社會上的好多中介也可以理解成為代理,說白了就是幫你辦事,拿中介費而已。
1、在這里,先把買票這個活動定義成一個接口(BuyTicket)類:
public interface BuyTicket {
? public void? buyTicket();
}
2、下面我們要對這兩個接口進行實現
A:正常情況下的買票活動(NormalBuyTicket)類:
public class NormalBuyTicket implements BuyTicket{
? public void? buyTicket(){
???? System.out.println("買火車票!");
? }
}
B:代理情況下的買票活動(ProxyBuyTicket)類:
//當不能直接訪問NormalBuyTicket對象時,必須要用代理對象
public class ProxyBuyTicket implements BuyTicket{
? private NormalBuyTicket normalBuyTicket;
? public void? buyTicket(){
???? if(normalBuyTicket==null){
?????? normalBuyTicket = new NormalBuyTicket();
???? }
???? normalBuyTicket.buyTicket();
???? getMoney();
? }
? public void getMoney(){
???? System.out.println("獲得代理費!");
? }
}
3、編寫測試類:
public class Test {
? public static void? main(String args[]){
??? BuyTicket buyTicket = new ProxyBuyTicket();
??? buyTicket.buyTicket();
? }
}
4、說明:
A:定義:為其他對象提供一種代理以控制對這個對象的訪問。也就是說當我們不能直接訪問我們想訪問的對象時,必須通過一個代理對象來訪問。
B:在本例中,我想買票,但當我直接買不到票時,就只好通過票販子來買,這個道理應該誰都知道啊。
5、后記:
最終通過票販子,我獲得了去上海的票,老婆很高興,還說我很能干,但是我付出了100元的代理費,我到底該哭還是該笑呢,但又想一下:"花100元讓老婆表揚我,說我很能干,也不錯啊,你說呢!嘿嘿"。
十一、設計模式之Prototype——作業篇
今年要交作業,可是由于我這幾天沉迷于CS之中,到現在還沒寫作業,這可該怎么辦呢,誰都知道我們老師最討厭不寫作業的學生了。嘿嘿,還好我有一門優秀的技能,那就是——Clone大法(俗稱COPY大法),正是由于擁有該技能,才能使我殘酷的斗爭中立于不敗之地。于是我以迅雷不及眼耳盜鈴之勢拿來了張三的作業,開始運功。
說道這里就不得不先說說什么叫Clone?
有一個對象A,在某一時刻A中已經包含了一些有效值,此時可能會需要一個和A完全相同新對象B,并且此后對B任何改動都不會影響到A中的值,也就是說,A與B是兩個獨立的對象,但B的初始值是由A對象確定的。
好了言歸正傳,讓我們開始吧。
?
1、在這里,先定義一個拷貝作業(CopyHomeWork)接口:
public interface CopyHomeWork extends Cloneable{
? public String getHomeWork() ;
? public void setHomeWork(String homeWork);
}
2、再定義一個作業(HomeWork)的實現類:
public abstract class HomeWork implements CopyHomeWork{
? String homeWork;
?
? public void setHomeWork(String homeWork) {
??? this.homeWork = homeWork;
? }
?
? public String getHomeWork() {
??? return this.homeWork;
? }
?
// 典型的調用clone()代碼
? public Object clone() {
??? Object object = null;
??? try {
????? object = super.clone();
??? }
??? catch (CloneNotSupportedException exception) {
????? System.err.println("*** is not Cloneable");
??? }
??? return object;
? }
?
? public abstract void? DoHomeWork();? //做作業的抽象類
?
}
3、定義張三的作業(ZhangSanHomeWork)類:
public class ZhangSanHomeWork extends HomeWork{
?
? public void DoHomeWork() {
????? System.out.println("張三作完了作業!");
? }
?
}
4、編寫測試類:
public class TestCopyHomeWork {
? public static void? main(String args[]){
??? ZhangSanHomeWork zhangsanHomeWork = new ZhangSanHomeWork();
??? HomeWork myHomeWork = (HomeWork)zhangsanHomeWork.clone();
??? myHomeWork.DoHomeWork();
??? myHomeWork.setHomeWork("我正在抄作業,請勿打擾!");
??? System.out.println(myHomeWork.getHomeWork());
? }
}
5、說明:
A:定義:用原型實例指定創建對象的種類,并且通過拷貝這些原型創建新的對象。
B:Prototype模式允許一個對象再創建另外一個可定制的對象,根本無需知道任何如何創建的細節,工作原理是:通過將一個原型對象傳給那個要發動創建的對象,這個要發動創建的對象通過請求原型對象拷貝它們自己來實施創建。
C:Prototype模式最終演變成clone的使用。
十二、設計模式之Facade——家庭篇
今年十一國慶節,我呆在家里美美的享受了一下家的溫馨。首先讓我來介紹一下我的家庭成員:
妻子(Wife)
女兒(Daughter)
我(My)
我們都是家庭(Family)的一分子,我們是以家庭對外的。就象我們國家對外是以"中國",外國人都稱我們是中國人,但在中國這個大家庭內部,包括了漢、回、蒙、。。。等56個民族一樣。
可見對外我們是要以統一的身份,或叫統一的外觀(Facade)進行展現。
好了言歸正傳。
1、? 在這里,先定義家庭的各個成員類:
妻子(Wife):
public class Wife {
? public Wife() {
??? System.out.println("老婆偉大 !");
? }
}
女兒(Daughter):
public class Daughter {
? public Daughter () {
??? System.out.println("女兒可愛 !");
? }
}
我(My):
public class My {
? public My () {
??? System.out.println("我愛我家 !");
? }
}
2、定義家庭對外展現(FamilyOutShow)類:
public class FamilyOutShow {
? public void MyFamily() {
??? Wife myWife = new Wife();
??? Daughter myDaughter = new Daughter ();
??? My mySelf = new My();
? }
}
3、編寫測試類:
public class MyFamilyTest {
? public static void main(String[] args) {
????? FamilyOutShow myFamily = new FamilyOutShow ();
????? myFamily.MyFamily();
? }
}
4、說明:
A:Facade的定義: 為子系統中的一組接口提供一個一致的界面。
B:使用統一對外接口,可以降低系統的復雜性,增加了靈活性。
C:從例子中可以看到,外界只是訪問了家庭對外展現(FamilyOutShow)類,而沒有直接與成員類打交道。這樣比如說增加了一個新的成員類(比如說兒子(Son)類),只要修改家庭對外展現(FamilyOutShow)類即可,而不用修改調用。
十三、設計模式之Decorator——家裝篇
最近家里搞裝修,做了一套家具,需要刷一下漆,因此我就去市場找了油漆師傅和油漆徒弟兩個人。
油漆師傅主要買油漆和調油漆,油漆徒弟主要來刷油漆(團隊精神?哈哈,不禁讓讓我想起CS,你先沖,我揀菜。)。
1、在這里,我們先把這個油漆工作定義成一個接口類:
public interface Work
{
? public void? brush();?? //刷油漆
}
?
2、因為油漆師傅和油漆徒弟的任務是刷油漆,因此他們要對Work接口進行實現:
A:油漆徒弟
刷油漆的工作主要是由油漆徒弟來完成,所以我們把油漆徒弟定義成Brusher(油漆師傅在一旁說:"徒弟嗎,就是要多干活。",油漆徒弟小聲嘀咕:"多你個頭。")。
public class Brusher implements Work{
? public void brush() {
??? System.out.println("刷油漆");
? }
}
B:油漆師傅
我們把油漆師傅定義成Decorator。
public class Decorator implements Work{
? private Work work;
//油漆師傅的工作被放置在這個List中
? private ArrayList prework = new ArrayList();
//油漆師傅的默認工作
? public Decorator(Work work) {
??? this.work = work;
??? prework.add("買油漆");
??? prework.add("調油漆");
? }
?
? public void brush() {//刷油漆, 油漆師傅也要實現此方法
??? newWork();???????? //當油漆師傅接到活,就開始一個新的工作
? }
?
//新的工作
? public void newWork() {
??? preWork();????? //油漆師傅做的前期輔助工作
??? work.brush();?? //讓徒弟干的刷油漆的工作
? }
?
//油漆師傅做的前期輔助工作
? public void preWork() {
??? ListIterator listIterator = prework.listIterator();
??? while (listIterator.hasNext()) {
????? System.out.println( ( (String) (listIterator.next())) + "完成");
??? }
? }
3、編寫測試類:
public class test {
? public static void? main(String args[]) {
??? Work bursher = new Brusher();
??? Work decorator = new Decorator(bursher);
??? decorator.brush();
?? //我把活交給油漆師傅,油漆師傅下來再把實際刷油漆的工作指派給油漆徒弟干
? }
?
4、說明:
A:代碼只用來學習Decorator模式,要運行的話,必須要做一點改動。
B:在這過程中,我只和油漆師傅打交道,具體的刷油漆那是由油漆師傅和油漆徒弟之間的事,我是不用關心的。
C:使用Decorator的理由是:這些功能需要由用戶動態決定加入的方式和時機.Decorator提供了"即插即用"的方法,在運行期間決定何時增加何種功能.
十四、設計模式之Visitor——送禮篇
今年過年不收禮,收禮只收腦白金。聽到這暗示性的廣告詞,我的腦袋突然一亮。因為最近因為要辦某事,必須要給單位的領導要表示一下。到底送什么,還真讓人頭痛,還好有腦白金,奶奶的。。。,腐敗啊,罪過!
首先要對送禮的對象進行分析,單位有兩個領導,一正,一副。因此給不同的領導送的禮也是不同的(哈,收入要和產出成正比嗎),好了言歸正傳。
1、在這里,先把領導定義成一個接口類:
public interface Leader{
? public void accept(Visitor visitor);? //主要任務----收visitor(拜訪者)的禮
}
在把拜訪者定義成另一個接口類:
public interface Visitor
{
?? public void visitFirstHand(FirstHand first);? //拜訪一把手(帶的禮物)
?? public void visitSecondHand(SecondHand second);? //拜訪二把手(帶的禮物)
?? public void visitCollection(Collection collection);? //判斷是拜訪一把手還是二把手
}
2、下面我們要對這兩個接口進行實現:
A:一把手
public class FirstHand implements Leader {
? private String value; //注意此處是String
? public FirstHand (String string) {//一把手的構造函數
??? value = string;
? }
?
? public String getValue() { //獲得禮物
??? return value;
? }
?
//定義accept的具體內容 這里是很簡單的一句調用
? public void accept(Visitor visitor) {
??? visitor.visitFirstHand (this);? //接收拜訪人送的禮
? }
}
B:二把手
public class SecondHand implements Leader {
? private Float value; //注意此處是Float
? public SecondHand (Float string) {//二把手的構造函數
??? value = string;
? }
?
? public Float getValue() { //獲得禮物
??? return value;
? }
?
//定義accept的具體內容 這里是很簡單的一句調用
? public void accept(Visitor visitor) {
??? visitor.visitFirstHand (this);? //接收拜訪人送的禮
? }
}
C:拜訪人(我)
public class visitMe implements Visitor{
? public void visitCollection(Collection collection) {
????? Iterator iterator = collection.iterator();
????? while (iterator.hasNext()) {
?????????????? Object o = iterator.next();
???????? if (o instanceof Leader)???????? //判斷要送給哪個領導
????????? ((Leader)o).accept(this);???? //不同的領導進入不同的實現類
????? }
??? }
??? public void visitFirstHand (FirstHand first) {
????? System.out.println("送的禮是:"+ first.getValue());
??? }
??? public void visitSecondHand (SecondHand second) {
????? System.out.println("送的禮是:" + second.getValue());
??? }
}
3、編寫測試類:
public class test {
?? public static void? main(String args[]){
???? Visitor visitor = new visitMe ();
???? FirstHand present = new FirstHand ("十盒腦白金");
???? visitor.visitFirstHand (present);
?
???? Collection list = new ArrayList();
???? list.add(new FirstHand ("十盒腦白金"));
???? list.add(new SecondHand (new Float("一斤小點心"))); //為了說明不同,如要運行,要做類型轉換。
???? visitor.visitCollection(list);
?
?? }
?
4、說明:
A:代碼只用來學習Visitor模式,要運行的話,必須要做一點改動。
B:FirstHand,SecondHand只是一個個具體實現,實際上還可以拓展為更多的實現,整個核心奧妙在accept方法中,在遍歷Collection時,通過相應的accept方法調用具體類型的被訪問者。這一步確定了被訪問者類型
C:使用訪問者模式是對象群結構中(Collection) 中的對象類型很少改變,也就是說領導很少變化。
十五、設計模式之Builder——購機篇
最近想買一臺電腦用于學習,因此我就去了一家電腦公司,經過分析,選用了下面的配置:
CPU??? P2.4
主板?? Intel
硬盤?? 80G
。。。
買過電腦的朋友可能都知道,我們選好配置后,電腦公司就會有專門的組裝師(Assembler)來給我們裝機。電腦(Computer)就是由這些東西(我們稱之為Part)組成的。學過經濟學的朋友可能都知道,如果這臺組裝好的電腦不賣掉,那它就不是商品(Commodity),而僅僅是臺電腦而已。
1、? 在這里,我們先定義商品(Commodity)類:
public class Commodity {
? String commodity ="";
? public Commodity (Part partA,Part partB,Part partC) {//由各個部分組成
??? this. commodity = partA.part+"\n";
??? this. commodity = product+partB.part+"\n";
??? this. commodity = product+partC.part;
??? System.out.println("我的機器配置為:\n"+ commodity);
? }
}
2、? 下來我們再定義電腦的組成部分(Part)類:
public class Part {
? String part="";
? public Part(String part){
??? this.part = part;
? }
}
3、? 我們把電腦(Computer)定義成一個接口類:
public interface Computer {
//組裝部件A 比如CPU
? void buildPartA();
?
//組裝部件B? 比如主板
? void buildPartB();
?
//組裝部件C? 比如硬盤
? void buildPartC();
?
//返回最后組裝成品結果 (返回最后組裝好的電腦)
//成品的組裝過程不在這里進行,而是由組裝師(Assembler)類完成的。
//從而實現了過程和部件的分離
? Product getProduct();
}
4、? 定義電腦的組裝師(Assembler)類:
public class Assembler {
? private Computer computer;
? public Assembler(Computer computer) {? //主要任務是裝電腦
??? this.computer = computer;
? }
?
// 將部件partA partB partC最后組成復雜對象
//這里是將主板、CPU和硬盤組裝成PC的過程
? public void construct() {
??? computer.buildPartA();
??? computer.buildPartB();
??? computer.buildPartC();
? }
}
5、? 我的電腦是對電腦(Computer)接口的具體實現,因此再定義MyComputer實現類:
public class MyComputer implements Computer {
? Part partA, partB, partC;
? public void buildPartA() {
??? partA = new Part("P42.4 CPU");
? }
? public void buildPartB() {
??? partB = new Part("Inter 主板");
? }
? public void buildPartC() {
??? partC = new Part("80G硬盤");
? }
? public Product getProduct() {
//返回最后組裝成品結果
??? Commodity myComputer = new Commodity (partA,partB,partC);
??? return myComputer;
? }
}
6、? 編寫測試類:
public class MyComputerTest {
? public static void? main(String args[]){
??? MyComputer myComputer = new MyComputer();????? //組裝我的電腦
??? Assembler assembler = new Assembler( myComputer );? //派某一位組裝師
??? assembler.construct();??? //組裝師進行組裝過程
??? Commodity commodity = myComputer.getProduct();?? //賣給我的電腦(商品)
? }
}
7、說明:
A:代碼只用來學習Builder模式,要運行的話,必須要做一點改動。
B:將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。因為每個人的電腦配置可能都是不同的。
C:我們使用Builer是為了構建復雜對象的過程和它的部件解耦,也就是說將過程分的盡可能細,而且每一部分只用完成自己的功能即可(各司其職嘛)。
十六、設計模式之Factory——買貨篇
今天老婆讓我去市場買一些水果,具體買什么自己定(哈,老婆放放權了!)。來到市場,我發現主要有一些水果:蘋果(Apple),葡萄(Grape)和鴨梨(Pear)。
到底買什么好呢?我一陣思量。俗話說:"飯后一只煙,賽過活神仙。飯后吃蘋果,西施見我躲。"為了老婆的漂亮,我決定買蘋果。
好,言歸正傳,開始買吧!
?
主要有以下三種Factory模式:
Simple Factory模式
專門定義一個類來負責創建其它類的實例,被創建的實例通常都具有共同的父類。
Factory Method模式
將對象的創建交由父類中定義的一個標準方法來完成,而不是其構造函數,究竟應該創建何種對象由具體的子類負責決定。
Abstract Factory模式
提供一個共同的接口來創建相互關聯的多個對象。
?
一、Simple Factory模式:
1、? 在這里,我們先定義水果(Fruit)接口:
public interface Fruit {
? void plant();? //水果是被種植的
? void enableEat();? //水果能吃
}
2、? 蘋果(Apple)是對水果(Fruit)接口的實現:
public class Apple implements Fruit{
? public void plant(){
??? System.out.println("種蘋果!");
? }
? public void enableEat(){
??? System.out.println("蘋果好吃!");
? }
}
3、? 葡萄(Grape)是對水果(Fruit)接口的實現:
public class Grape implements Fruit{
? public void plant(){
??? System.out.println("種葡萄!");
? }
? public void enableEat(){
??? System.out.println("葡萄好吃!");
? }
}
4、? 鴨梨(Pear)是對水果(Fruit)接口的實現:
public class Pear implements Fruit{
? public void plant(){
??? System.out.println("種鴨梨!");
? }
? public void enableEat(){
??? System.out.println("鴨梨好吃!");
? }
}
5、定義買水果(BuyFruit)這一過程類:
public class BuyFruit {
? /**
? * 簡單工廠方法
? */
? public static Fruit buyFruit(String which){
??? if (which.equalsIgnoreCase("apple")) {? //如果是蘋果,則返回蘋果實例
????? return new Apple();
??? }
??? else if (which.equalsIgnoreCase("pear")){? //如果是鴨梨,則返回鴨梨實例
????? return new Strawberry();
??? }
??? else if (which.equalsIgnoreCase("grape")) { //如果是葡萄,則返回葡萄實例
????? return new Grape();
??? }
??? else{
????? return null;
??? }
? }
}
6、? 編寫測試類:
public class FruitTest {
? public static void? main(String args[]){
??? BuyFruit buy = new BuyFruit();?? //開始買水果這個過程
??? buy.buyFruit("apple").enableEat(); //調用蘋果的enableEat()方法
? }
}
7、? 說明:
A:我要購買蘋果,只需向工廠角色(BuyFruit)請求即可。而工廠角色在接到請求后,會自行判斷創建和提供哪一個產品。
B:但是對于工廠角色(BuyFruit)來說,增加新的產品(比如說增加草莓)就是一個痛苦的過程。工廠角色必須知道每一種產品,如何創建它們,以及何時向客戶端提供它們。換言之,接納新的產品意味著修改這個工廠。
C:因此Simple Factory模式的開放性比較差。
有什么辦法可以解決這個問題嗎?那就需要Factory Method模式來為我們服務了。
二、Factory Method模式:
1、同樣,我們先定義水果(Fruit)接口:
public interface Fruit {
? void plant();? //水果是被種植的
? void enableEat();? //水果能吃
}
2、蘋果(Apple)是對水果(Fruit)接口的實現:
public class Apple implements Fruit{
? public void plant(){
??? System.out.println("種蘋果!");
? }
? public void enableEat(){
??? System.out.println("蘋果好吃!");
? }
}
3、葡萄(Grape)是對水果(Fruit)接口的實現:
public class Grape implements Fruit{
? public void plant(){
??? System.out.println("種葡萄!");
? }
? public void enableEat(){
??? System.out.println("葡萄好吃!");
? }
}
4、鴨梨(Pear)是對水果(Fruit)接口的實現:
public class Pear implements Fruit{
? public void plant(){
??? System.out.println("種鴨梨!");
? }
? public void enableEat(){
??? System.out.println("鴨梨好吃!");
? }
}
5、在這里我們將買水果(BuyFruit)定義為接口類:
public interface BuyFruit{
? /**
? * 工廠方法
? */
? public Fruit buyFruit();?? //定義買水果這一過程
}
6、買蘋果是(BuyApple)對買水果(BuyFruit)這個接口的實現
public class BuyApple implements BuyFruit{
? public Fruit buyFruit(){
??? return new Apple();? //返回蘋果實例
}
}
7、買鴨梨是(BuyPear)對買水果(BuyFruit)這個接口的實現
public class BuyPear implements BuyFruit{
? public Fruit BuyPear (){
??? return new Pear();? //返回鴨梨實例
}
}
8、買葡萄是(BuyGrape)對買水果(BuyFruit)這個接口的實現
public class BuyGrape implements BuyFruit{
? public Fruit BuyGrape (){
??? return new Grape ();? //返回葡萄實例
}
}
9、編寫測試類:
public class FruitTest {
? public static void? main(String args[]){
??? BuyApple buy = new BuyApple(); //開始買水果這個過程
??? buy.buyFruit().enableEat();????? //調用蘋果的enableEat()方法
? }
}
10、說明:
A:工廠方法模式和簡單工廠模式在結構上的不同是很明顯的。工廠方法模式的核心是一個抽象工廠類,而簡單工廠模式把核心放在一個具體類上。工廠方法模式可以允許很多具體工廠類從抽象工廠類中將創建行為繼承下來,從而可以成為多個簡單工廠模式的綜合,進而推廣了簡單工廠模式。
B:工廠方法模式退化后可以變得很像簡單工廠模式。設想如果非常確定一個系統只需要一個具體工廠類,那么就不妨把抽象工廠類合并到具體的工廠類中去。由于反正只有一個具體工廠類,所以不妨將工廠方法改成為靜態方法,這時候就得到了簡單工廠模式。C:如果需要加入一個新的水果,那么只需要加入一個新的水果類以及它所對應的工廠類。沒有必要修改客戶端,也沒有必要修改抽象工廠角色或者其他已有的具體工廠角色。對于增加新的水果類而言,這個系統完全支持"開-閉"原則。
D:對Factory Method模式而言,它只是針對一種類別(如本例中的水果類Fruit),但如果我們還想買肉,那就不行了,這是就必須要Factory Method模式幫忙了。
三、Abstract Factory模式
1、同樣,我們先定義水果(Fruit)接口:
public interface Fruit {
? void plant();? //水果是被種植的
? void enableEat();? //水果能吃
}
2、蘋果(Apple)是對水果(Fruit)接口的實現:
public class Apple implements Fruit{
? public void plant(){
??? System.out.println("種蘋果!");
? }
? public void enableEat(){
??? System.out.println("蘋果好吃!");
? }
}
3、葡萄(Grape)是對水果(Fruit)接口的實現:
public class Grape implements Fruit{
? public void plant(){
??? System.out.println("種葡萄!");
? }
? public void enableEat(){
??? System.out.println("葡萄好吃!");
? }
}
4、鴨梨(Pear)是對水果(Fruit)接口的實現:
public class Pear implements Fruit{
? public void plant(){
??? System.out.println("種鴨梨!");
? }
? public void enableEat(){
??? System.out.println("鴨梨好吃!");
? }
}