
前言
大部分的面試者在IT行業面試中,提及設計模式,可以列舉一大堆,但是面試官要求細說的時候,往往部分基礎不夠牢固的同學只能提及簡單工廠,今天我們來對面試程序中最常見的簡單工廠、工廠方法和抽象工廠進行一個剖析,喜歡的朋友可以點個關注哦,
正文
在面向物件的編程中,一般通過繼承和虛函式來提供抽象能力,多型讓程式在執行期,呼叫者只需要看到父型別別,而不需要關心繼承的子型別別,舉個例子: 比如有個游戲,里面的游戲的活動物件為動物,比如有老虎和貓,會對主人公進行攻擊,那么可能會實作為如下:

代碼如下:
class Animal
{
public:
virtual void Attack() = 0;
};
class Tiger : public Animal
{
public:
virtual void Attack() { std::cout << "Tiger Attack!" << std::endl; };
};
class Cat : public Animal
{
public:
virtual void Attack() { std::cout << "Cat Attack!" << std::endl; };
};
那如果在外面有個方法,并不需要關心具體的物件型別,只需要使用基類Animal的指標去操作物件, 利用多型機制變可以實作對具體物件型別的方法呼叫:
void Attack(Animal* pAnimal)
{
pAnimal->Attack();
}
比如這個時候采用如下方法進行呼叫(忽略里面記憶體釋放的問題):
Animal* pAnimal = new Tiger;
Attack(pAnimal);
pAnimal = new Cat;
Attack(pAnimal);
輸出結果為:
Tiger Attack!
Cat Attack!
上面多型例子說明了在程式實作的時候只需要操控Animal,知道其方法即可操作繼承自Animal的物件,那么也就是說:
-
繼承自Animal的Cat和Tiger的不需要暴露給使用者
-
可以屏蔽Cat和Tiger的創建程序,不需要被呼叫者所關心
那么這個時候模塊化和工廠設計模式可以對其進行實作:
-
比如將Animal, Cat, Tiger的實作都放進一個元件的模塊中,并且只暴露Animal的頭檔案給呼叫者
-
而工廠方法設計模式,可以使用一個工廠方法創建具體的物件,回傳的時候只回傳基類Animal的指標,
本文將先從簡單工廠說起,然后再談一談工廠方法以及抽象工廠,
簡單工廠
我相信這個是大家最常見的一種實作方法,如下:

class AnimalFactory
{
public:
enum class AnimalType
{
TIGER,
CAT
};
static Animal* CreateAnimal(const AnimalType type)
{
if (AnimalType::TIGER == type)
{
return new Tiger;
}
else if (AnimalType::CAT == type)
{
return new Cat;
}
return nullptr;
}
};
呼叫方法如下:
Animal* pAnimal = AnimalFactory::CreateAnimal(AnimalFactory::AnimalType::TIGER);
Attack(pAnimal);
pAnimal = AnimalFactory::CreateAnimal(AnimalFactory::AnimalType::CAT);
Attack(pAnimal);
但是這種方式違背了軟體開發原則的開閉原則(Open-Closed Principle, OCP),如果你需要新增一個叫做Dog的物件,則需要在CreateAnimal方法中修改分支判斷邏輯,簡單來說這種擴展方式,破壞了原有的邏輯,擴展中可能對軟體的原有的穩定性產生影響,
可能有些人是不能夠容忍代碼,但也有人認為這種書寫方式比較簡單,從我個人在工程實踐經驗,認為軟體開發設計原則是有非常好的指導性意義,但是也并不是所有的代碼一定要符合軟體開發的設計原則,個人的理解大致如下:
-
工程實踐中有時候為了代碼完全遵循軟體開發設計原則,反而是有負擔的,比如過度設計問題,一來有些代碼模塊可能甚至幾年都不會對其進行修改擴展了,二來當邏輯實作比較簡單的時候,過度設計也會讓代碼維護的人閱讀代碼實際是更加費勁的,畢竟大多數人都只是普通的程式員,
-
往往可擴展的代碼撰寫時間是更長的,但是壓在程式員頭上的還有軟體開發時間,對于一般的程式員來說,在規定時間內,有質量的完成需求是第一位的,而這個時候很可能就不會完全照顧軟體開發設計原則了,
如果要符合開閉原則,那么我們可以實作工廠方法模式,讓我們一起來看看吧,
工廠方法
工廠方法的主要是通過繼承一個AnimalFactory來實作具體的工廠,比如CatFatory主要負責生產Cat,而TigerFacotory主要負責生產Tiger,其類圖如下:

代碼如下:
class AnimalFactory
{
public:
virtual Animal* CreateAnimal() = 0;
};
class CatFactory : public AnimalFactory
{
public:
virtual Animal* CreateAnimal()
{
return new Cat;
}
};
class TigerFactory : public AnimalFactory
{
public:
virtual Animal* CreateAnimal()
{
return new Tiger;
}
};
呼叫方式如下代碼:
AnimalFactory* pFactory = new TigerFactory;
Animal* pAnimal = pFactory->CreateAnimal();
Attack(pAnimal);
pFactory = new CatFactory;
pAnimal = pFactory->CreateAnimal();
Attack(pAnimal);
可以發現工廠方法模式如果需要擴展一個新的動物型別,也可以對應擴展一個新的工廠,比如增加一個新的DogFactory繼承AnimalFactory去生產Dog,從而符合開閉原則,更加安全的進行擴展,但是這種方式也可以看出來,每增加一個新的動物型別就得新增一個Fatory,個人對這種模式理解如下:
-
當這種動物型別創建并不是很繁瑣的時候,采用這種方式相比較簡單工程而言會繁瑣一些;但是當初始化程序比較多的時候,用工廠方法模式方式擴展會顯得更加清晰;
-
這種設計模式的本身實作是取消了條件判斷的邏輯,但是其實是把這個條件判斷任務交給了使用者去判斷選擇哪個工廠了,
抽象工廠
對于新手來說可能不太好理解抽象工廠模式,容易和工廠方法模式混淆起來,工廠方法模式中的每一個工廠是生產一個動物角色,而在抽象工廠中是生產一類動物角色的抽象,
一個動物角色比較好理解,就是我們上面的CatFactory生產Cat角色, 而TigerFactory生產Tiger角色,
一類動物角色,我們可以理解在這個游戲中,這些動物角色的攻擊性也分普通模式和困難模式,
那么我們首先要將Tiger分成SimpleModeTiger和HardModeTiger; Cat分為SimpleModeCat和HardModeCat,然后抽象工廠提供CreateAnimal的介面,繼承的SimpleModeFactory可以生產簡單模式的Cat角色和Tiger角色,繼承的HardModeFactory可以生產困難模式的Cat角色和Tiger角色,

實作的代碼如下所示:
#include <iostream>
class Animal
{
public:
virtual void Attack() = 0;
};
class AbstructTiger : public Animal
{
public:
virtual void Attack() = 0;
};
class SimpleModeTiger : public AbstructTiger
{
public:
virtual void Attack() { std::cout << "Tiger Simple Attack!" << std::endl; }
};
class HardModeTiger : public AbstructTiger
{
public:
virtual void Attack() { std::cout << "Tiger Hard Attack!" << std::endl; }
};
class AbstructCat : public Animal
{
public:
virtual void Attack() = 0;
};
class SimpleModeCat : public AbstructCat
{
public:
virtual void Attack() { std::cout << "Cat Simple Attack!" << std::endl; }
};
class HardModeCat : public AbstructCat
{
public:
virtual void Attack() { std::cout << "Cat Hard Attack!" << std::endl; }
};
enum class AnimalType
{
TIGER,
CAT
};
class AbscractAnimalFactory
{
public:
virtual Animal* CreateAnimal(const AnimalType type) = 0;
};
class SimpleModeAnimalFactory : public AbscractAnimalFactory
{
public:
virtual Animal* CreateAnimal(const AnimalType type)
{
if (AnimalType::TIGER == type)
{
return new SimpleModeTiger;
}
else if (AnimalType::CAT == type)
{
return new SimpleModeCat;
}
return nullptr;
}
};
class HardModeAnimalFactory : public AbscractAnimalFactory
{
public:
virtual Animal* CreateAnimal(const AnimalType type)
{
if (AnimalType::TIGER == type)
{
return new HardModeTiger;
}
else if (AnimalType::CAT == type)
{
return new HardModeCat;
}
return nullptr;
}
};
void Attack(Animal* pAnimal)
{
pAnimal->Attack();
}
int main()
{
//簡單模式
AbscractAnimalFactory* pFactory = new SimpleModeAnimalFactory;
Animal* pAnimal = pFactory->CreateAnimal(AnimalType::TIGER);
Attack(pAnimal);
pAnimal = pFactory->CreateAnimal(AnimalType::CAT);
Attack(pAnimal);
//困難模式
pFactory = new HardModeAnimalFactory;
pAnimal = pFactory->CreateAnimal(AnimalType::TIGER);
Attack(pAnimal);
pAnimal = pFactory->CreateAnimal(AnimalType::CAT);
Attack(pAnimal);
}
為了讓結構簡單便于讀者理解抽象工廠模式,以及和工廠方法模式的區別,上面的SimpleModeFactory和HardModeFactory用的是簡單工廠的形式實作的,如果需要符合開閉原則,可以再對SimpleModeFactory和HardModeFactory進行工廠方法的實作,可以想象如果抽象工廠再加上工廠方法這個類的結構是有多么的龐大,而且這還僅僅只是兩個游戲角色的描述,所以筆者認為在做工程實踐的時候,盡量不要做過度設計,有時候反而不利于代碼閱讀,修改也未必簡單,自己要權衡好工程和理論的平衡點,
結尾
好了,今天的內容就到此為止了,感謝各位看官,喜歡的朋友可以點贊,收藏,評論,當然,如果能給我個關注那就最好不過了,這樣的話就不會錯過我的日更投稿哦,你的支持就是我最大的動力,感謝各位,那么我們明天見,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/448173.html
標籤:設計模式
上一篇:JDK動態代理
下一篇:設計模式之享元模式
