設計模式之禪(4)-工廠模式
文章目錄
更多關於設計模式的文章請點選:設計模式之禪(0)-目錄頁
工廠模式(Factory Pattern)是 Java 中最常用的設計模式之一。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。
一、簡單工廠模式
1.1、單一new方式
我們在開發專案時如果需要獲取物件,通常會使用單一new的方式去獲取它:
Object object1 = new Object1();
Object object2 = new Object2();
Object object3 = new Object3();
我們或許還會在創建出來後進行一些處理:
Object object1 = new Object1();
object1.setA(A);
object1.setB(B);
Object object2 = new Object2();
object2. setA(A);
object2.setB(B);
Object object3 = new Object3();
object3.setA(A);
object3.setB(B);
這會暴露出一個問題:
所有的建立過程和固定的操作都需要寫出來,並且在原生代碼中將其暴露。這不符合寫入不變的、封裝變化的程式碼的設計模式,所以說,我們需要一個類似於工廠的角色去產生這些物件,並且對它們進行一些固定的操作。這樣就自然而然地引出了簡單工廠模式(Simple Factory Pattern
)。
1.2、簡單工廠模式
簡單工廠模式(Simple Factory Pattern
)的使用很簡單,再拿我們的動物簡單工廠來舉例子:
public class SimpleAnimalFactory{
public Animal getAnimal(String type){
if(type.equals("Dog")){
Animal dog = new Dog();
//處理dog
return dog ;
}else if(type.equals("Cat")){
Animal cat= new Cat();
//處理cat
return cat;
}
}
}
當我們需要Dog時,只需要建立SimpleAnimalFactory,再用其呼叫getAnimal(“Dog”)即可獲得一隻"經過處理的狗",而且這些建立和處理對"呼叫者"來說是"不可見"的,呼叫者並不在乎工廠內部到底做了什麼,只需要獲得經過處理的物件。
那麼,工廠模式就這樣講完了嗎?當然不是。其實,簡單工廠模式並不算是一種設計模式,工廠模式也遠沒那麼簡單。
二、抽象工廠及工廠方法
2.1、將簡單工廠改造成抽象工廠
在上面的簡單工廠中,我們所實現的SimpleAnimalFactory已經能幫助我們獲得簡單的動物了,但是當我們需要動物園的動物時,我們需要製造一個ZooAnimalFactory;同理,當我們需要野生動物時,我們需要WildAnimalFactory,我們可以這樣寫:
- ZooAnimalFactory
public class ZooAnimalFactory{
public Animal getAnimal(String type) {
if(type.equals("ZooDog")){
return new ZooDog();
}else if(type.equals("ZooCat")){
return new ZooCat();
}
return null;
}
}
- WildAnimalFactory
public class WildAnimalFactory{
public Animal getAnimal(String type) {
if(type.equals("WildDog")){
return new WildDog();
}else if(type.equals("WildCat")){
return new WildCat();
}
return null;
}
}
如果你需要其他各種各樣的工廠,我們只能一遍又一遍地寫著,那麼為什麼我們不能抽取出來一個動物工廠超類,讓其他工廠去繼承它,獲得工廠所需的方法和屬性呢?這就是抽象工廠:
- AnimalFactory
public abstract class AnimalFactory {
public abstract Animal getAnimal(String type);
}
}
此時,我們的ZooAnimalFactory和WildAnimalFactory可以這樣寫:
- ZooAnimalFactory
public class ZooAnimalFactory extends AnimalFactory{
@Override
public Animal getAnimal(String type) {
if(type.equals("ZooDog")){
return new ZooDog();
}else if(type.equals("ZooCat")){
return new ZooCat();
}
return null;
}
}
- WildAnimalFactory
public class WildAnimalFactory extends AnimalFactory{
@Override
public Animal getAnimal(String type) {
if(type.equals("WildDog")){
return new WildDog();
}else if(type.equals("WildCat")){
return new WildCat();
}
return null;
}
}
2.2、為抽象工廠中添加工廠方法
我們上面的抽象工廠已經可以滿足基本的需求了,但是還有一點美中不足:工廠中的動物由getAnimal(String type)方法建立,這裡頭真正產生動物的程式碼沒有被封裝起來,這就是所謂的工廠方法,即真正產生出物件的方法,我們可以在抽象工廠中新增一個工廠方法createAnimal(String type)
,並且讓子類去重寫這個工廠方法。
- AnimalFactory
/**
* @Auther: ARong
* @Date: 2018/11/25 19:34
* @Description: 動物工廠超類
*/
public abstract class AnimalFactory {
public Animal getAnimal(String type){
//呼叫createAnimal方法,該方法由實現類去重寫
Animal animal = createAnimal(type);
return animal;
}
protected abstract Animal createAnimal(String type);
}
三、工廠模式總結
以上工廠模式的類,可以用簡單的UML關係圖來表示:
- AnimalFactory
/**
* @Auther: ARong
* @Date: 2018/11/25 19:34
* @Description: 動物工廠超類
*/
public abstract class AnimalFactory {
public Animal getAnimal(String type){
//呼叫createAnimal方法,該方法由實現類去重寫
Animal animal = createAnimal(type);
return animal;
}
protected abstract Animal createAnimal(String type);
}
- ZooAnimalFactory
/**
* @Auther: ARong
* @Date: 2018/11/25 19:36
* @Description: AnimalFactory的實現類
*/
public class ZooAnimalFactory extends AnimalFactory{
//按需重寫createAnimal方法
@Override
protected Animal createAnimal(String type) {
if(type.equals("ZooDog")){
return new ZooDog();
}else if(type.equals("ZooCat")){
return new ZooCat();
}
return null;
}
}
- WildAnimalFactory
/**
* @Auther: ARong
* @Date: 2018/11/25 19:41
* @Description: AnimalFactory的實現類,野生動物工廠
*/
public class WildAnimalFactory extends AnimalFactory{
@Override
protected Animal createAnimal(String type) {
if(type.equals("WildDog")){
return new WildDog();
}else if(type.equals("WildCat")){
return new WildCat();
}
return null;
}
}
- Animal
/**
* @Auther: ARong
* @Date: 2018/11/17 11:08
* @Description:動物的抽象類,定義動物的屬性以及抽象行為和具體行為
*/
public abstract class Animal {
//動物名稱
private String name;
//定義run方法
public abstract void run();
//get、set
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
-
ZooCat/ZooDog/WildCat/WildDog的程式碼不列出了
-
測試
/**
* @Auther: ARong
* @Date: 2018/11/25 19:44
* @Description: 動物工廠測試
*/
public class TestAnimalFactory {
@Test
public void getZooAnimal(){
AnimalFactory zooAnimalFactory = new ZooAnimalFactory();
Animal zooDog = zooAnimalFactory.getAnimal("ZooDog");
zooDog.run();
}
@Test
public void getWildAnimal(){
AnimalFactory wildAnimalFactory = new WildAnimalFactory();
Animal wildCat = wildAnimalFactory.getAnimal("WildCat");
wildCat.run();
}
}