工厂模式(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)
参考资料: