從前有一座山叫爪媧山屑迂,山峰上住著一個(gè)神龍見首不見尾的道士浸策,江湖上的外號(hào)叫攝計(jì)魔士,他在密室里放著一座煉丹爐惹盼。(抱著娛樂的精神庸汗,類名方法名有一些用了中文命名,不規(guī)范手报。在Head First Design Pattern這本書里面蚯舱,舉了一個(gè)Pizza店的例子,我覺得很不錯(cuò)掩蛤。我想了如下這個(gè)不同的例子枉昏,來說明同樣的問題。)本文系原創(chuàng)<br />
為什么需要工廠模式?使用工廠模式有什么好處揍鸟?可以解決什么問題兄裂?
煉丹第一重境界:
攝計(jì)魔士剛?cè)胄袝r(shí),涉世不深阳藻,只會(huì)煉一種丹晰奖,所以煉丹的代碼比較簡(jiǎn)陋
public class 丹 {
public static 丹 makeDan() {
丹 dan = new 丹();
dan.準(zhǔn)備();
dan.煉制();
dan.收工();
return dan;
}
private void 收工() {
System.out.println("七七四十九天,九九八十一輪回稚配,神丹已成畅涂,請(qǐng)您享用");
}
private void 煉制() {
System.out.println("麻利麻利哄,煉制過程開始道川。午衰。。");
}
private void 準(zhǔn)備() {
System.out.println("準(zhǔn)備開始煉丹");
}
}
測(cè)試丹.makeDan();
冒萄,運(yùn)行結(jié)果如下
煉丹第二重境界:(靜態(tài)工廠方法)
隨著煉丹水平的提升臊岸,攝計(jì)魔士學(xué)會(huì)了用不同的元素?zé)挼?br>
丹.class
public class 丹 {
static 丹 makeDan(String element) {
丹 dan = null;
if (element.equals("金")) {
dan = new 金丹();
} else if (element.equals("銀")) {
dan = new 銀丹();
} else if (element.equals("銅")) {
dan = new 銅丹();
} else if (element.equals("宋丹")) {
dan = new 宋丹丹();
}
if (dan != null) {
dan.準(zhǔn)備();
dan.煉制();
dan.收工(element);
}
return dan;
}
public void 收工(String element) {
System.out.println("七七四十九天,九九八十一輪回尊流," + element + "丹已成帅戒,請(qǐng)您享用\n");
}
public void 煉制() {
System.out.println("麻利麻利哄,煉制過程開始崖技。逻住。。");
}
public void 準(zhǔn)備() {
System.out.println("準(zhǔn)備開始煉丹");
}
}
DanTestDrive.class
public class DanTestDrive {
public static void main(String[] args) {
丹.makeDan("金");
丹.makeDan("宋丹");
}
}
運(yùn)行結(jié)果:
煉丹第三重境界:(簡(jiǎn)單工廠)
丹.class
interface 丹 {
public void 收工();
public void 煉制();
public void 準(zhǔn)備();
}
金丹.class
public class 金丹 implements 丹 {
@Override
public void 收工() {
System.out.println("煉制完成迎献,用上等的鎏金獸牙盒包裝\n");
}
@Override
public void 煉制() {
System.out.println("金丹煉制中...");
}
@Override
public void 準(zhǔn)備() {
System.out.println("加入黃金二兩瞎访,秘方若干兩");
}
}
銀丹.class
public class 銀丹 implements 丹 {
@Override
public void 收工() {
System.out.println("煉制完成,用陳年黑檀木盒包裝\n");
}
@Override
public void 煉制() {
System.out.println("銀丹煉制中....");
}
@Override
public void 準(zhǔn)備() {
System.out.println("加入白銀二兩吁恍,秘方若干兩");
}
}
煉丹密室.class
public class 煉丹密室 {
簡(jiǎn)丹工廠 factory;
public 煉丹密室(簡(jiǎn)丹工廠 factory) {
this.factory = factory;
}
public 丹 makeDan(String element) {
丹 dan;
dan = factory.createDan(element);
dan.準(zhǔn)備();
dan.煉制();
dan.收工();
return dan;
}
}
簡(jiǎn)丹工廠.class
public class 簡(jiǎn)丹工廠 {
丹 createDan(String element) {
丹 dan = null;
if (element.equals("金")) {
dan = new 金丹();
} else if (element.equals("銀")) {
dan = new 銀丹();
} else if (element.equals("銅")) {
dan = new 銅丹();
} else if (element.equals("宋丹")) {
dan = new 宋丹丹();
}
return dan;
}
}
測(cè)試類
public class DanTestDrive {
public static void main(String[] args) {
煉丹密室 煉丹密室 = new 煉丹密室(new 簡(jiǎn)丹工廠());
煉丹密室.makeDan("金");
煉丹密室.makeDan("銀");
}
}
運(yùn)行結(jié)果:
結(jié)構(gòu)圖:
煉丹第四重境界1:(工廠模式)
攝計(jì)魔士帶的幾個(gè)徒弟都出師了扒秸,他們是思聰播演、御鳳、強(qiáng)東伴奥、芙蓉四大煉丹術(shù)士写烤,雖然師出同門,但他們每個(gè)人煉丹都有自己的風(fēng)格拾徙,原來一間小小的煉丹密室已經(jīng)不夠用了洲炊。<br />
原先是在煉丹密室的構(gòu)造函數(shù)中,傳入簡(jiǎn)丹工廠的引用锣吼,然后在煉丹密室的makeDan方法中选浑,調(diào)用簡(jiǎn)丹工廠中的createDan()(dan = factory.createDan(element);
)蓝厌,以得到不同種類的丹玄叠,現(xiàn)在因?yàn)橥降艹鰩熈耍瑤煾副仨氃诟叩膶哟紊蟻碓O(shè)計(jì)煉丹的標(biāo)準(zhǔn)拓提。createDan從簡(jiǎn)丹工廠中移到煉丹密室中读恃,并使之成為抽象方法,從而煉丹密室成為一個(gè)抽象類<br />
在此例中可見代态,“煉丹密室”這個(gè)類運(yùn)用了工廠方法模式寺惫,它定義了一個(gè)創(chuàng)建對(duì)象的接口(createDan),具體要實(shí)例化的類(丹類)是哪一個(gè)蹦疑,是由繼承“煉丹密室”的子類所決定的西雀。工廠方法讓類的實(shí)例化推遲到子類中。這樣歉摧,在煉丹密室這個(gè)父類中艇肴,所做的是制定流程的事,把不變的部分放在其中叁温,比如將丹類的三個(gè)方法按順序排好再悼,丹需要先準(zhǔn)備、然后煉制膝但,最后收工冲九。但是具體的實(shí)現(xiàn)過程,因丹而異(比如強(qiáng)東的金丹跟束,他要放入狗糧和奶茶粉的配料)莺奸。不能將變動(dòng)的內(nèi)容放入到煉丹密室中,每種具體的實(shí)現(xiàn)冀宴,都由每種不同的丹的子類去實(shí)現(xiàn)灭贷。
煉丹密室.class
public abstract class 煉丹密室 {
public 丹 makeDan(String element) {
丹 dan;
dan = createDan(element);
dan.準(zhǔn)備();
dan.煉制();
dan.收工();
return dan;
}
protected abstract 丹 createDan(String element);
}
思聰?shù)臒挼っ苁?class
public class 思聰?shù)臒挼っ苁?extends 煉丹密室 {
@Override
protected 丹 createDan(String element) {
if (element.equals("金")) {
return new 思聰?shù)拿刂平鸬?);
} else if (element.equals("銀")) {
return new 思聰?shù)拿刂沏y丹();
} else {
return null;
}
}
}
思聰?shù)拿刂沏y丹.class
public class 思聰?shù)拿刂沏y丹 implements 丹 {
@Override
public void 收工() {
System.out.println("銀丹煉制完成,用明成化斗彩雞缸杯來裝\n");
}
@Override
public void 煉制() {
System.out.println("銀丹煉制中...");
}
@Override
public void 準(zhǔn)備() {
System.out.println("思聰秘制銀丹煉制準(zhǔn)備花鹅。氧腰。枫浙。");
System.out.println("放入銀兩,再加兩斤鉆石磨成粉");
}
}
強(qiáng)東的煉丹密室.class
public class 強(qiáng)東的煉丹密室 extends 煉丹密室 {
@Override
protected 丹 createDan(String element) {
if (element.equals("金")) {
return new 強(qiáng)東的秘制金丹();
} else if (element.equals("銀")) {
return new 強(qiáng)東的秘制銀丹();
} else {
return null;
}
}
}
強(qiáng)東的秘制金丹.class
public class 強(qiáng)東的秘制金丹 implements 丹 {
@Override
public void 收工() {
System.out.println("用上等的塑料袋包裝\n");
}
@Override
public void 煉制() {
System.out.println("金丹煉制中古拴,等6月18日來拿...");
}
@Override
public void 準(zhǔn)備() {
System.out.println("強(qiáng)東的金丹鋪?zhàn)娱_張啦箩帚。。黄痪。");
System.out.println("金丹準(zhǔn)備紧帕,加一點(diǎn)點(diǎn)奶茶粉");
}
}
測(cè)試類
public class DanTestDrive {
public static void main(String[] args) {
煉丹密室 sicongRoom = new 思聰?shù)臒挼っ苁?);
sicongRoom.makeDan("銀");
煉丹密室 qiangdongRoom = new 強(qiáng)東的煉丹密室();
qiangdongRoom.makeDan("金");
}
}
輸出結(jié)果:
煉丹第四重境界2:(工廠模式)
師父一看徒弟們煉的丹,完全隨心所欲桅打,他決定在質(zhì)量上面增加一點(diǎn)點(diǎn)把控是嗜,于是他做了一些改變,首先就是把原先“丹”由接口變成抽象類
丹.class
public abstract class 丹 {
String name;
String roomName;
String creatorName;
String packageName;
List<String> additions = new ArrayList<String>();
public String getName() {
return name;
}
public void 收工() {
System.out.println("煉制完成挺尾," + name + "將由" + packageName + "包裝\n");
}
public void 煉制() {
System.out.println(name + "正在煉制中鹅搪。。遭铺。");
}
public void 準(zhǔn)備() {
System.out.println("爪媧山煉丹密室之" + roomName + "開始煉丹丽柿。。魂挂。");
System.out.println("接下來將由" + creatorName + "大師開始煉制" + name);
System.out.println("架爐生火");
System.out.println("接下來放入" + roomName + "的秘制配方:");
for (int i = 0; i < additions.size(); i++) {
System.out.println(" " + (i+1) + ":" + additions.get(i));
}
}
}
強(qiáng)東的秘制銀丹.class
public class 強(qiáng)東的秘制銀丹 extends 丹 {
public 強(qiáng)東的秘制銀丹() {
name = "強(qiáng)東的秘制銀丹";
roomName = "強(qiáng)東的煉丹密室";
creatorName = "強(qiáng)東";
packageName = "塑料袋";
additions.add("奶茶粉");
additions.add("狗糧");
}
}
思聰?shù)拿刂沏y丹.class
public class 思聰?shù)拿刂沏y丹 extends 丹 {
public 思聰?shù)拿刂沏y丹() {
name = "思聰?shù)拿刂沏y丹";
roomName = "思聰?shù)臒挼っ苁?;
creatorName = "思聰";
packageName = "斗彩雞缸杯";
additions.add("鉆石粉");
additions.add("一打iphone");
additions.add("隕石");
}
}
測(cè)試類
public class DanTestDrive {
public static void main(String[] args) {
煉丹密室 sicongRoom = new 思聰?shù)臒挼っ苁?);
sicongRoom.makeDan("銀");
煉丹密室 qiangdongRoom = new 強(qiáng)東的煉丹密室();
qiangdongRoom.makeDan("銀");
}
}
輸出結(jié)果:
結(jié)構(gòu)圖
煉丹第五重境界:(抽象工廠模式)
一山不容二虎甫题,徒兒們漸漸翅膀長(zhǎng)硬了,于是都想著要各奔東西了涂召。原本煉丹坠非,第一味總是要先加入師父提供的秘方,才能夠煉制成功果正。不管是金丹還是銀丹炎码,都需要加入它,這味秘方被稱為“丹魂”(不是混蛋)舱卡,即丹的靈魂的意思辅肾。攝計(jì)魔士知道徒兒們的心思,于是意味深長(zhǎng)地和徒兒們道出了秘方:丹魂是由三種東西構(gòu)成的:清晨的露水轮锥,白色的羽毛以及若干種獸骨矫钓,唯有丹魂,才有神丹舍杜。金丹的丹魂是清晨的露水新娜、白色的羽毛及若干種獸骨 ,銀丹的丹魂是清晨的露水和白色的羽毛既绩,銅丹的丹魂只需要清晨的露水概龄。
金丹 | 銀丹 | 銅丹 | |
---|---|---|---|
清晨的露水 | √ | √ | √ |
白色的羽毛 | √ | √ | <br /> |
若干種獸骨 | √ | <br /> | <br /> |
其中御鳳去了亞美利加大洲,她煉制金丹時(shí)饲握,用了美洲雕的羽毛私杜,清晨中央公園嫩葉上的露水以及火雞骨和北美的野牛骨作為丹魂蚕键。而思聰則留在了大陸,他煉制金丹時(shí)衰粹,用了蘭博基尼上的新鮮露水锣光、白鳳凰的羽毛以及麒麟、獬豸和貔貅骨頭作為丹魂铝耻。
丹魂工廠.class
public interface 丹魂工廠 {
public 露水 createDew();
public 羽毛 createFeather();
public 獸骨[] createBones();
public 金 createGold();
public 銀 createSilver();
public 銅 createBronze();
}
思聰?shù)せ旯S.class
public class 思聰?shù)せ旯S implements 丹魂工廠 {
@Override
public 露水 createDew() {
return new 蘭博基尼上的新鮮露水();
}
@Override
public 羽毛 createFeather() {
return new 白鳳凰羽();
}
@Override
public 獸骨[] createBones() {
獸骨[] bones = {new 麒麟骨(), new 獬豸骨(), new 貔貅骨()};
return bones;
}
@Override
public 金 createGold() {
return new 金();
}
@Override
public 銀 createSilver() {
return new 銀();
}
@Override
public 銅 createBronze() {
return new 銅();
}
}
御鳳丹魂工廠.class
public class 御鳳丹魂工廠 implements 丹魂工廠 {
@Override
public 露水 createDew() {
return new 中央公園新鮮露水();
}
@Override
public 羽毛 createFeather() {
return new 美洲雕白羽();
}
@Override
public 獸骨[] createBones() {
獸骨[] bones = {new 火雞骨(), new 北美野牛骨()};
return bones;
}
@Override
public 金 createGold() {
return new 金();
}
@Override
public 銀 createSilver() {
return new 銀();
}
@Override
public 銅 createBronze() {
return new 銅();
}
}
丹.class
該類與之前的區(qū)別就在于誊爹,將“準(zhǔn)備()”變成了一個(gè)抽象方法,由子類去實(shí)現(xiàn)
public abstract class 丹 {
String name;
String roomName;
String creatorName;
String packageName;
露水 dew;
羽毛 feather;
獸骨[] bones;
金 gold;
銀 silver;
銅 bronze;
List<String> additions = new ArrayList<String>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void 收工() {
System.out.println("煉制完成瓢捉," + name + "將由" + packageName + "包裝\n");
}
public void 煉制() {
System.out.println(name + "正在煉制中频丘。。泡态。");
}
abstract void 準(zhǔn)備();
}
金丹.class
public class 金丹 extends 丹 {
丹魂工廠 ingredientFactory;
public 金丹(丹魂工廠 ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
void 準(zhǔn)備() {
System.out.println("開始煉制" + name);
dew = ingredientFactory.createDew();
feather = ingredientFactory.createFeather();
bones = ingredientFactory.createBones();
gold = ingredientFactory.createGold();
System.out.println("構(gòu)成金丹的丹魂是:" +
dew.getClass().getSuperclass().getSimpleName() + "搂漠、" +
feather.getClass().getSuperclass().getSimpleName() + "和獸骨"
);
System.out.println(name + "的丹魂配方由"
+ dew.getClass().getSimpleName() + "、"
+ feather.getClass().getSimpleName() + "以及若干獸骨所組成"
);
System.out.println("其中獸骨的配方包含:");
for (int i = 0; i < bones.length; i++) {
System.out.println(" " + (i + 1) + "." + bones[i].getName());
}
}
}
銀丹.class
public class 銀丹 extends 丹 {
丹魂工廠 ingredientFactory;
public 銀丹(丹魂工廠 ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
public void 準(zhǔn)備() {
System.out.println("開始煉制" + name);
dew = ingredientFactory.createDew();
feather = ingredientFactory.createFeather();
silver = ingredientFactory.createSilver();
System.out.println("構(gòu)成銀丹的丹魂是:"
+ dew.getClass().getSuperclass().getSimpleName() + "和"
+ feather.getClass().getSuperclass().getSimpleName());
System.out.println(name + "的丹魂配方由"
+ dew.getClass().getSimpleName() + "兽赁、"
+ feather.getClass().getSimpleName() + "所組成"
);
}
}
思聰?shù)拿刂沏y丹.class
public class 思聰?shù)拿刂沏y丹 extends 銀丹 {
public 思聰?shù)拿刂沏y丹(丹魂工廠 ingredientFactory) {
super(ingredientFactory);
packageName = "斗彩雞缸杯";
}
}
思聰?shù)拿刂平鸬?class
public class 思聰?shù)拿刂平鸬?extends 金丹 {
public 思聰?shù)拿刂平鸬?丹魂工廠 ingredientFactory) {
super(ingredientFactory);
packageName = "斗彩雞缸杯";
}
}
御鳳的秘制金丹.class
public class 御鳳的秘制金丹 extends 金丹 {
public 御鳳的秘制金丹(丹魂工廠 ingredientFactory) {
super(ingredientFactory);
packageName = "首飾盒";
}
}
煉丹密室.class
public abstract class 煉丹密室 {
public 丹 makeDan(String element) {
丹 dan;
dan = createDan(element);
dan.準(zhǔn)備();
dan.煉制();
dan.收工();
return dan;
}
protected abstract 丹 createDan(String element);
}
思聰?shù)臒挼っ苁?class
public class 思聰?shù)臒挼っ苁?extends 煉丹密室 {
@Override
protected 丹 createDan(String element) {
丹 dan = null;
丹魂工廠 ingredientFactory = new 思聰?shù)せ旯S();
if (element.equals("金")) {
dan = new 思聰?shù)拿刂平鸬?ingredientFactory);
dan.setName("思聰金丹");
} else if (element.equals("銀")) {
dan = new 思聰?shù)拿刂沏y丹(ingredientFactory);
dan.setName("思聰銀丹");
} else if (element.equals("銅")) {
dan = new 銅丹(ingredientFactory);
dan.setName("思聰銅丹");
}
return dan;
}
}
御鳳的煉丹密室.class
public class 御鳳的煉丹密室 extends 煉丹密室 {
@Override
protected 丹 createDan(String element) {
丹 dan = null;
丹魂工廠 ingredientFactory = new 御鳳丹魂工廠();
if (element.equals("金")) {
dan = new 御鳳的秘制金丹(ingredientFactory);
dan.setName("御鳳金丹");
} else if (element.equals("銀")) {
dan = new 御鳳的秘制銀丹(ingredientFactory);
dan.setName("御鳳銀丹");
}
return dan;
}
}
測(cè)試類
public class DanTestDrive {
public static void main(String[] args) {
煉丹密室 sicongRoom = new 思聰?shù)臒挼っ苁?);
sicongRoom.makeDan("金");
sicongRoom.makeDan("銀");
煉丹密室 yufengRoom = new 御鳳的煉丹密室();
yufengRoom.makeDan("金");
}
}
運(yùn)行結(jié)果:
有一天思聰心血來潮状答,想用一下御鳳的丹魂配方冷守,于是他只用改一個(gè)地方刀崖,即把思聰?shù)せ旯S改成御鳳丹魂工廠。神奇的事情就發(fā)生了拍摇,只需要改動(dòng)一處亮钦,他的配方就變成了御鳳的配方。
思聰?shù)臒挼っ苁?class
public class 思聰?shù)臒挼っ苁?extends 煉丹密室 {
@Override
protected 丹 createDan(String element) {
丹 dan = null;
丹魂工廠 ingredientFactory = new 御鳳丹魂工廠();
if (element.equals("金")) {
dan = new 思聰?shù)拿刂平鸬?ingredientFactory);
dan.setName("思聰金丹");
} else if (element.equals("銀")) {
dan = new 思聰?shù)拿刂沏y丹(ingredientFactory);
dan.setName("思聰銀丹");
} else if (element.equals("銅")) {
dan = new 銅丹(ingredientFactory);
dan.setName("思聰銅丹");
}
return dan;
}
}
運(yùn)行結(jié)果:
丹魂工廠這個(gè)類便是運(yùn)用了抽象工廠模式充活,它以接口的形式提供出了一份創(chuàng)建對(duì)象的協(xié)議蜂莉,其中是丹魂的配方,包含露水混卵、白色羽毛和獸骨組合映穗。它只是說丹魂需要這三種成份,具體是用紐約中央公園的新鮮露水還是蘭博基尼上面的新鮮露水幕随,它不需要管蚁滋,由其子類來具體實(shí)現(xiàn),比如御鳳丹魂工廠赘淮、思聰?shù)せ旯S辕录。
結(jié)構(gòu)示意圖