工廠模式(Factor Pattern),就是負責生成其他對象的類或方法,也叫工廠方法模式
抽象工廠模式( Abstract Factor Pattern),可簡單理解爲工廠模式的升級版
(一)爲什麼需要工廠模式
1,工廠模式可以將對象的生產從直接new 一個對象,改成通過調用一個工廠方法生產。這樣的封裝,代碼若需修改new的對象時,不需修改多處new語句,只需更改生產對象方法。
2,若所需實例化的對象可選擇來自不同的類,可省略if-else多層判斷,給工廠方法傳入對應的參數,利用多態性,實例化對應的類。
(二)工廠模式結構圖
1,工廠方法模式
2,抽象工廠模式
(三)簡單實現代碼
//工廠類
class Factor{
//生成對象方法
static function createDB(){
echo '我生產了一個DB實例';
return new DB;
}
}
//數據類
class DB{
public function __construct(){
echo __CLASS__.PHP_EOL;
}
}
$db=Factor::createDB();
(四)實現一個運算器
abstract class Operation{
abstract public function getVal($i, $j);
}
class Add extends Operation{
public function getVal($i, $j)
{
return $i + $j;
}
}
class Minus extends Operation{
public function getVal($i, $j)
{
return $i - $j;
}
}
class Multiplied extends Operation{
public function getVal($i, $j)
{
return $i * $j;
}
}
class Divide extends Operation{
public function getVal($i, $j)
{
if ($j == 0)
throw new Exception("被除數不能爲0");
return $i / $j;
}
}
class CalcFactor{
private static $operation;
public static function createOperation(string $operation){
switch ($operation){
case "+":
self::$operation = new Add();
break;
case "-":
self::$operation = new Minus();
break;
case "*":
self::$operation = new Multiplied();
break;
case "/":
self::$operation = new Divide();
break;
}
return self::$operation;
}
}
$calc = CalcFactor::createOperation('/');
echo $calc->getVal(1,0);
缺點:每增加一個乘法運算,除了需要增加一個乘法運算類之外,還得去工廠生產方法裏面添加對應的case代碼,違反了開放-封閉原則。
解決方法:
(1):通過傳入指定類名
abstract class Operation{
abstract public function getVal($i, $j);
}
class Add extends Operation{
public function getVal($i, $j)
{
return $i + $j;
}
}
class Minus extends Operation{
public function getVal($i, $j)
{
return $i - $j;
}
}
class Multiplied extends Operation{
public function getVal($i, $j)
{
return $i * $j;
}
}
class Divide extends Operation{
public function getVal($i, $j)
{
if ($j == 0)
throw new Exception("被除數不能爲0");
return $i / $j;
}
}
class CalcFactor{
public static function createOperation(string $operation){
return new $operation;
}
}
$calc = CalcFactor::createOperation("Divide");
echo $calc->getVal(1,1);
(2):通過抽象工廠模式
這裏順帶提一個問題:如果我係統還有個生產一個文本輸入器工廠,那麼那個工廠和這個計數器工廠又有什麼關係呢。
抽象高於實現
其實我們完全可以抽象出一個抽象工廠,然後將對應的對象生產交給子工廠實現。代碼如下:
// 抽象運算類
abstract class Operation{
abstract public function getVal($i, $j);
}
// 加法類
class Add extends Operation{
public function getVal($i, $j)
{
return $i + $j;
}
}
// 減法類
class Minus extends Operation{
public function getVal($i, $j)
{
return $i - $j;
}
}
// 乘法類
class Multiplied extends Operation{
public function getVal($i, $j)
{
return $i * $j;
}
}
// 除法類
class Divide extends Operation{
public function getVal($i, $j)
{
if ($j == 0)
throw new Exception("被除數不能爲0");
return $i / $j;
}
}
// 抽象工廠類
abstract class Factor{
abstract static function getInstance();
}
// 加法工廠類
class AddFactor extends Factor {
public static function getInstance()
{
return new Add();
}
}
// 減法工廠類
class MinusFactor extends Factor {
public static function getInstance()
{
return new Minus();
}
}
// 乘法工廠類
class MultipliedFactor extends Factor {
public static function getInstance()
{
return new Multiplied();
}
}
// 除法工廠類
class DivideFactor extends Factor {
public static function getInstance()
{
return new Divide();
}
}
$divide = DivideFactor::getInstance();
echo $divide->getVal(1,1);
第四節 PHP設計模式(三)—外觀模式(門面模式)(Facade Pattern)
參考資料: