(原創)我眼中的設計模式系列之簡單工廠模式(一)
簡單工廠模式
在日常的軟件開發中,我們一般都是按照模塊來劃分工作的。
場景一:
試想我們現在有這麽一個模塊,為其他的模塊提供服務,比如說我們調用了好幾個外部接口,統一返回XML字符串,每個接口返回的XML格式都不同,有的嵌套數組,有的純數組,有的就是普通的節點XML。但是我們項目需要的是json格式的數據,通常的做法是寫幾個類,直接new出對象調用,或者交給spring管理進行註入。不管如何這幾個解析類都不是在同一個環境中,即使交由Spring管理,就站在這個模塊的角度中來說,這幾個類並並沒有形成自己的模塊化數據結構,而是分開和Spring的環境分散的耦合在一起了。代碼的結構會非常差。
場景二:
我們的業務模塊中需要的類有可能是不相關的,毫無聯系的,但是我們在一個比較大型的功能中需要同時用到這些類中的行為,這個時候我認為是可以使用工廠模式。即這些類實現同一個接口,使用工廠去維護他們,只針對我們需要的業務模塊的維護,工廠類可以交給Spring管理,作為這個工廠和Spirng的接口,相當於跟Spring的環境有關系但是又不耦合。
下面我舉個小例子可以說明工廠模式的使用,直接上代碼:
先創建具體行為的Animal接口
package com.bane.example1.executor; /** * * @ClassName: Animal * @Description: TODO(定義動物的接口) *@author 於繼偉 * @date 2017-10-20 下午10:06:49 * */ public interface Animal { }
創建具體動物行為的接口:
package com.bane.example1.executor; /** * * @ClassName: CatExecutor * @Description: TODO(Cat的行為接口) * @author 於繼偉 * @date 2017-10-20 下午10:02:29 * */ public interface CatExecutor extends Animal { /** * 抓老鼠的行為*/ void catchMouse(); }
package com.bane.example1.executor; /** * * @ClassName: DogExecutor * @Description: TODO(Dog的行為接口) * @author 於繼偉 * @date 2017-10-20 下午10:00:12 * */ public interface DogExecutor extends Animal { /** * 看家的方法 */ void door(); }
package com.bane.example1.executor; /** * * @ClassName: SnakeExecutor * @Description: TODO(Snake的行為接口) * @author 於繼偉 * @date 2017-10-20 下午10:04:46 * */ public interface SnakeExecutor extends Animal { /** * 咬人的行為 */ void bite(); }
再創建具體的實現:
package com.bane.example1.executor.impl; import com.bane.example1.executor.CatExecutor; /** * * @ClassName: CatExecutorImpl * @Description: TODO(貓具體行為的實現) * @author 於繼偉 * @date 2017-10-20 下午10:09:11 * */ public class CatExecutorImpl implements CatExecutor { @Override public void catchMouse() { System.out.println("抓老鼠"); } }
package com.bane.example1.executor.impl; import com.bane.example1.executor.DogExecutor; /** * * @ClassName: DogExecutorImpl * @Description: TODO(狗的行為的具體實現) * @author 於繼偉 * @date 2017-10-20 下午10:09:08 * */ public class DogExecutorImpl implements DogExecutor{ @Override public void door() { System.out.println("狗看家"); } }
package com.bane.example1.executor.impl; import com.bane.example1.executor.SnakeExecutor; /** * * @ClassName: SnakeExecutorImpl * @Description: TODO(蛇具體行為) * @author 於繼偉 * @date 2017-10-20 下午10:11:19 * */ public class SnakeExecutorImpl implements SnakeExecutor { @Override public void bite() { System.out.println("蛇咬人"); } }
工廠環境中的具體行為者有了,現在創建工廠的接口和實現:
package com.bane.example1.factory; import com.bane.example1.executor.Animal; /** * * @ClassName: AnimalFactory * @Description: TODO(簡單工廠接口) * @author 於繼偉 * @date 2017-10-20 下午9:57:46 * */ public interface AnimalFactory { /** * 根據類名創建Animal對象 * @param className * @return */ Animal createAnimal(String className); }
package com.bane.example1.factory.impl; import com.bane.example1.executor.Animal; import com.bane.example1.factory.AnimalFactory; /** * * @ClassName: AnimalFactoryImpl * @Description: TODO(動物工廠的具體實現) * @author 於繼偉 * @date 2017-10-20 下午10:14:03 * */ public class AnimalFactoryImpl implements AnimalFactory { @Override public Animal createAnimal(String className) { Animal animal = null; try { animal = (Animal) Class.forName(className).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return animal; } }
到此為止,我們的簡單工廠創建結束,將動物放入動物的工廠中,我們需要用的時候只需要從工廠中獲取動物的實例和行為,就可以使用了,測試類:
package com.bane.example1; import com.bane.example1.executor.CatExecutor; import com.bane.example1.executor.DogExecutor; import com.bane.example1.executor.SnakeExecutor; import com.bane.example1.factory.AnimalFactory; import com.bane.example1.factory.impl.AnimalFactoryImpl; /** * * @ClassName: Main * @Description: TODO(主方法測試) * @author 於繼偉 * @date 2017-10-20 下午10:21:48 * */ public class Main { public static void main(String[] args) { AnimalFactory animalFactory = new AnimalFactoryImpl(); CatExecutor catExecutor = (CatExecutor) animalFactory. createAnimal("com.bane.example1.executor.impl.CatExecutorImpl"); catExecutor.catchMouse(); DogExecutor dogExecutor = (DogExecutor) animalFactory. createAnimal("com.bane.example1.executor.impl.DogExecutorImpl"); dogExecutor.door(); SnakeExecutor snakeExecutor = (SnakeExecutor) animalFactory. createAnimal("com.bane.example1.executor.impl.SnakeExecutorImpl"); snakeExecutor.bite(); } }
控制臺輸出如下:
抓老鼠
狗看家
蛇咬人
需要說明的是,我們是用類名利用反射創建的實例,這樣可以省去if else的判斷,代碼更加優雅。至於需要用什麽樣的方式去創建或者什麽樣的條件,這個可以自己靈活使用。至此,簡單工廠到此為止。
靜態工廠
靜態工廠,其實跟上面的簡單工廠沒有任何的區別,無疑是工廠類中構造方法是私有的,方法都是靜態的。直接上代碼:
創建顏色的接口和具體的顏色實現:
package com.bane.example2.executor; /** * * @ClassName: Color * @Description: TODO(定義顏色行為接口) * @author 於繼偉 * @date 2017-10-21 下午12:11:28 * */ public interface Color { void show(); }
具體實現:
package com.bane.example2.executor.impl; import com.bane.example2.executor.Color; /** * * @ClassName: Blue * @Description: TODO(Blue具體實現) * @author 於繼偉 * @date 2017-10-21 下午12:13:17 * */ public class Blue implements Color{ @Override public void show() { System.out.println("這是藍色"); } }
package com.bane.example2.executor.impl; import com.bane.example2.executor.Color; /** * * @ClassName: Red * @Description: TODO(Red具體實現) * @author 於繼偉 * @date 2017-10-21 下午12:12:43 * */ public class Red implements Color{ @Override public void show() { System.out.println("我是紅色"); } }
package com.bane.example2.executor.impl; import com.bane.example2.executor.Color; /** * * @ClassName: Yellow * @Description: TODO(Yellow具體實現) * @author 於繼偉 * @date 2017-10-21 下午12:13:51 * */ public class Yellow implements Color{ @Override public void show() { System.out.println("這是黃色"); } }
最後創建我們的靜態工廠:
package com.bane.example2.factory; import com.bane.example2.executor.Color; /** * * @ClassName: ColorFactory * @Description: TODO(靜態工廠實現) * @author 於繼偉 * @date 2017-10-21 下午12:16:49 * */ public class ColorFactory { private ColorFactory(){} /** * 靜態工廠獲取Color對象的方法 * @param className * @return */ public static Color createColor(String className){ Color color = null; try { color = (Color) Class.forName(className).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return color; } }
最後主方法測試靜態工廠:
package com.bane.example2; import com.bane.example2.executor.Color; import com.bane.example2.factory.ColorFactory; /** * * @ClassName: Main * @Description: TODO(主方法測試靜態工廠) * @author 於繼偉 * @date 2017-10-21 下午12:19:14 * */ public class Main { public static void main(String[] args) { Color blue = ColorFactory.createColor ("com.bane.example2.executor.impl.Blue"); blue.show(); Color red = ColorFactory.createColor ("com.bane.example2.executor.impl.Red"); red.show(); Color yellow = ColorFactory.createColor ("com.bane.example2.executor.impl.Yellow"); yellow.show(); } }
控制臺輸出:
package com.bane.example2; import com.bane.example2.executor.Color; import com.bane.example2.factory.ColorFactory; /** * * @ClassName: Main * @Description: TODO(主方法測試靜態工廠) * @author 於繼偉 * @date 2017-10-21 下午12:19:14 * */ public class Main { public static void main(String[] args) { Color blue = ColorFactory.createColor ("com.bane.example2.executor.impl.Blue"); blue.show(); Color red = ColorFactory.createColor ("com.bane.example2.executor.impl.Red"); red.show(); Color yellow = ColorFactory.createColor ("com.bane.example2.executor.impl.Yellow"); yellow.show(); } }
控制臺輸出:
這是藍色
我是紅色
這是黃色
至此,靜態工廠結束。
抽象工廠
抽象工廠其實就是集中了好幾種的工廠,常用的例子是我們的家有廚房,衛生間,房間。這三個都可以看作工廠。廚房裏有菜刀,鍋等等,是具體的事物行為;衛生間有馬桶,淋浴頭等具體的事物行為;房間有衣櫃,床等具體的行為。今天我舉了一個更容易理解的例子。我們的公司有各個部門,例如行政部管的是後勤服務等等,財務部管的是財務和結算等等,開發部負責軟件的開發。公司就是一個抽象工廠,而這三個部門就是抽象工廠的具體工廠,抽象工廠定義行為,具體的工廠實現行為。至於我們剛才說的具體三個部門作為工廠,其實,每個部門內部還有很多員工和級別,這又可以繼續往下分和擴展,但是我們一般不會那麽做。因為那樣類的結構過於復雜,跟我們設計模式的初衷不相符。下面直接上代碼:
創建Department接口,沒有任何行為,主要是為了統一部門的表現形式
package com.bane.example3.executor; /** * * @ClassName: Company * @Description: TODO(公司的接口) * @author 於繼偉 * @date 2017-10-21 下午12:36:38 * */ public interface Department { }
具體部門接口:
package com.bane.example3.executor; /** * * @ClassName: CaiWuBuExecutor * @Description: TODO(財務部的行為接口) * @author 於繼偉 * @date 2017-10-21 下午12:29:14 * */ public interface CaiWuBuExecutor extends Department{ /** * 結算的方法 */ void jiesuan(); }
package com.bane.example3.executor; /** * * @ClassName: KaiFabuExecutor * @Description: TODO(開發部的行為接口) * @author 於繼偉 * @date 2017-10-21 下午12:28:42 * */ public interface KaiFabuExecutor extends Department { /** * 開發的方法 */ void kaifa(); }
package com.bane.example3.executor; /** * * @ClassName: XingZhengBuExecutor * @Description: TODO(行政部的行為接口) * @author 於繼偉 * @date 2017-10-21 下午12:29:33 * */ public interface XingZhengBuExecutor extends Department { /** * 後勤的方法 */ void houqin(); }
部門的具體實現:
package com.bane.example3.executor.impl; import com.bane.example3.executor.CaiWuBuExecutor; /** * * @ClassName: CaiWuBuExecutorImpl * @Description: TODO(財務部具體實現) * @author 於繼偉 * @date 2017-10-21 下午12:47:44 * */ public class CaiWuBuExecutorImpl implements CaiWuBuExecutor { @Override public void jiesuan() { System.out.println("財務部負責結算"); } }
package com.bane.example3.executor.impl; import com.bane.example3.executor.KaiFabuExecutor; /** * * @ClassName: KaiFabuExecutorImpl * @Description: TODO(開發部具體實現) * @author 於繼偉 * @date 2017-10-21 下午12:48:17 * */ public class KaiFabuExecutorImpl implements KaiFabuExecutor { @Override public void kaifa() { System.out.println("開發部負責開發"); } }
package com.bane.example3.executor.impl; import com.bane.example3.executor.XingZhengBuExecutor; /** * * @ClassName: XingZhengBuExecutorImpl * @Description: TODO(行政部具體實現) * @author 於繼偉 * @date 2017-10-21 下午12:48:48 * */ public class XingZhengBuExecutorImpl implements XingZhengBuExecutor { @Override public void houqin() { System.out.println("行政部負責後勤"); } }
跟之前一樣,具體的行為有了,可以定義工廠類了:
package com.bane.example3.factory; import com.bane.example3.executor.CaiWuBuExecutor; import com.bane.example3.executor.KaiFabuExecutor; import com.bane.example3.executor.XingZhengBuExecutor; /** * * @ClassName: AbstractFactory * @Description: TODO(抽象工廠) * @author 於繼偉 * @date 2017-10-21 下午12:23:46 * */ public abstract class AbstractCompanyFactory { /** * 構建財務部 * @param className * @return */ public CaiWuBuExecutor createCaiwuBu(String className){return null;} /** * 構建開發部 * @param className * @return */ public KaiFabuExecutor createKaiFabu(String className){return null;} /** * 構建行政部 * @param className * @return */ public XingZhengBuExecutor createXingZhengBu(String className){return null;} }
package com.bane.example3.factory.sub; import com.bane.example3.executor.CaiWuBuExecutor; import com.bane.example3.executor.Department; import com.bane.example3.factory.AbstractCompanyFactory; /** * * @ClassName: CaiWuBuFactory * @Description: TODO(財務部的工廠) * @author 於繼偉 * @date 2017-10-21 下午12:26:53 * */ public class CaiWuBuFactory extends AbstractCompanyFactory { @Override public CaiWuBuExecutor createCaiwuBu(String className) { Department department = null; try { department = (Department) Class.forName(className).newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return (CaiWuBuExecutor) department; } }
package com.bane.example3.factory.sub; import com.bane.example3.executor.Department; import com.bane.example3.executor.KaiFabuExecutor; import com.bane.example3.factory.AbstractCompanyFactory; /** * * @ClassName: KaiFaBuFactory * @Description: TODO(開發部的工廠) * @author 於繼偉 * @date 2017-10-21 下午12:25:53 * */ public class KaiFaBuFactory extends AbstractCompanyFactory { @Override public KaiFabuExecutor createKaiFabu(String className) { Department department = null; try { department = (Department) Class.forName(className).newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return (KaiFabuExecutor) department; } }
package com.bane.example3.factory.sub; import com.bane.example3.executor.Department; import com.bane.example3.executor.XingZhengBuExecutor; import com.bane.example3.factory.AbstractCompanyFactory; /** * * @ClassName: XingZhengBuFactory * @Description: TODO(行政部的工廠) * @author 於繼偉 * @date 2017-10-21 下午12:26:12 * */ public class XingZhengBuFactory extends AbstractCompanyFactory{ @Override public XingZhengBuExecutor createXingZhengBu(String className) { Department department = null; try { department = (Department) Class.forName(className).newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return (XingZhengBuExecutor) department; } }
最後寫主方法測試:
package com.bane.example3; import com.bane.example3.executor.CaiWuBuExecutor; import com.bane.example3.executor.KaiFabuExecutor; import com.bane.example3.executor.XingZhengBuExecutor; import com.bane.example3.factory.AbstractCompanyFactory; import com.bane.example3.factory.sub.CaiWuBuFactory; import com.bane.example3.factory.sub.KaiFaBuFactory; import com.bane.example3.factory.sub.XingZhengBuFactory; /** * * @ClassName: Main * @Description: TODO(抽象工廠測試) * @author 於繼偉 * @date 2017-10-21 下午12:22:48 * */ public class Main { public static void main(String[] args) { //1.獲取具體的工廠 //財務部的工廠 AbstractCompanyFactory caiwuFactory = new CaiWuBuFactory(); //開發部的工廠 AbstractCompanyFactory kaifaFactory = new KaiFaBuFactory(); //行政部的工廠 AbstractCompanyFactory xingZhengFactory = new XingZhengBuFactory(); //2.從工廠中獲取具體的部門職能 //財務職能 CaiWuBuExecutor caiwu = caiwuFactory.createCaiwuBu ("com.bane.example3.executor.impl.CaiWuBuExecutorImpl"); //開發職能 KaiFabuExecutor kaifa = kaifaFactory.createKaiFabu ("com.bane.example3.executor.impl.KaiFabuExecutorImpl"); //後勤職能 XingZhengBuExecutor xingzheng = xingZhengFactory.createXingZhengBu ("com.bane.example3.executor.impl.XingZhengBuExecutorImpl"); caiwu.jiesuan(); kaifa.kaifa(); xingzheng.houqin(); } }
控制臺輸出:
財務部負責結算
開發部負責開發
行政部負責後勤
上面就是我們工廠模式常用的三種表現形式,從上面的代碼我們不難看出接口的作用,面向接口編程是JAVA開發中非常重要的一個理念,或者說是思想,根據SOA的思想來說,暴露出來的一定是接口,接口實現的對象類型的控制和擴展,在面向對象程序的設計中具有非常至關重要的意義。至於面向接口編程,大家可以搜索一下相關的文章去閱讀。
其實我們的Spring就是一個非常大的工廠模式,閱讀過源碼的同學可以知道,Spring基於BeanFactory,創建出Bean,但是又維護著自己的數據結構,源於工廠,但是比工廠的設計復雜太多太多。工廠模式我的理解就是這樣。
(原創)我眼中的設計模式系列之簡單工廠模式(一)