2014年读过有关设计模式的书籍,当时在写C#程序,很受益。
可惜,当时没有再深入、仔细地研读和总结,后面基本上没有写代码了,也就没有看了。
去年开始学习使用PHP,需要把这一块认真地捡起来了。
虽然设计模式与开发语言关系不大,但是语言的差异还是会影响到设计模式的具体实现细节。
面向对象编程,也就是创建对象、对象的组合(搭建)以及交互,对应的设计模式就是创建型、结构型以及行为型,总共有23种。
简单工厂、工厂、抽象工厂属于设计模式中的创建型。
简单理解:
① 简单工厂模式就是一个工厂生产多个产品。
② 工厂就是每个工厂生产单一的产品。
③ 抽象工厂就是每个工厂生产多个产品。
1、简单工厂模式
就是一个生产对象根据用户给定的数据生产指定的用户对象。
生产对象就是工厂,给定的数据可以是数字或者字符串,用户对象就是产品。
代码如下:
<?php
class BaseObj{}
class ObjA extends BaseObj{}
class ObjB extends BaseObj{}
class simpleFactory{
public function GetProduct($ObjName){
switch($ObjName){
case "A":
return new ObjA();
break;
case "B":
return new ObjB();
break;
default:
return null;
break;
}
}
}
$NewObj=(new simpleFactory)->GetProduct("B");
echo get_class($NewObj);
?>
输出:
ObjB
上面的表述比较简单、清晰,要点:
⑴ 所有的产品只由一个工厂产生。
⑵ 所有的产品继承自同一个基础产品类。
设计模式的细节展开,根据不同的解读有不同的表现形式,比如面向接口的编程,产品都具有相同的行为特征,代码可以变化为产品都实现同一类的接口:
<?php
interface IStandard{
public function init();
}
class ObjA implements IStandard{
public function init(){
return "产品A";
}
}
class ObjB implements IStandard{
public function init(){
return "产品B";
}
}
class simpleFactory{
public static function GetProduct($ProductName){
switch($ProductName){
case "A":
return new ObjA();
break;
case "B":
return new ObjB();
break;
default:
return null;
break;
}
}
}
$NewObj=simpleFactory::GetProduct("A");
echo get_class($NewObj);
?>
输出:
ObjA
上面使用了静态方法,这样方便对象创建和后续的动作,比如可以统计总共创建了多少个产品以及不同的产品数量等。
面向抽象的编程,也只是产品描述有些变化:
<?php
abstract class BaseObj{
protected $Name;
public abstract function __construct();
public function show(){
return "这是".$this->Name."的输出信息";
}
}
class ObjA extends BaseObj{
public function __construct(){
$this->Name="产品A";
}
}
class ObjB extends BaseObj{
public function __construct(){
$this->Name="产品B";
}
}
class simpleFactory{
public static function GetProduct($ProductName){
switch($ProductName){
case "A":
return new ObjA();
break;
case "B":
return new ObjB();
break;
default:
return null;
break;
}
}
}
$NewObj=simpleFactory::GetProduct("A");
echo $NewObj->show();
?>
简单工厂只有一个生产对象,却生产了多个用户对象,根据面向对象编程中的单一职责原则,一个用户对象由一个对应的工厂来产生,这样就有了工厂模式。
2、工厂模式
就是每个生产对象专门生产它对应的用户对象。
这里的关键在于工厂如何与用户对象来关联。
用到了抽象。就是将工厂对象进行抽象,封装进行关联的抽象方法。
<?php
class BaseObj{ }
class ObjA extends BaseObj{ }
class ObjB extends BaseObj{ }
abstract class Factory{
protected $Name;
public abstract function __construct();
public function show(){
return "这是".$this->Name."的输出信息";
}
}
class FactoryA extends Factory{
public function __construct(){
$this->Name="产品A";
}
}
class FactoryB extends Factory{
public function __construct(){
$this->Name="产品B";
}
}
$NewObj=new FactoryB;
echo $NewObj->show();
?>
输出:
这是产品B的输出信息
这里我们也可以针对接口和抽象来改写上面的代码。
3、抽象工厂模式
就是每个生产对象专门生产它对应的多个用户对象。
这里的用户对象分别属于不同的产品类。
关键也是在每个工厂如何与用户对象来关联。我们可以将工厂要进行的生产(方法)抽象,后面继承而来的工厂必须实现具体的生产方法,也就是确定它要生产的对象。
一旦关联好了,那么指定了某个工厂以及工厂内的某个系列也就确定了属于它生产的用户对象。
代码:
<?php
class BaseObjA{ }
class BaseObjB{ }
class ObjA1 extends BaseObjA{ }
class ObjA2 extends BaseObjA{ }
class ObjB1 extends BaseObjB{ }
class ObjB2 extends BaseObjB{ }
abstract class Factory{
public abstract function CreateA();
public abstract function CreateB();
}
class Factory1 extends Factory{
public function CreateA(){
return new ObjA1;
}
public function CreateB(){
return new ObjB1;
}
}
class Factory2 extends Factory{
public function CreateA(){
return new ObjA2;
}
public function CreateB(){
return new ObjB2;
}
}
$NewObj=(new Factory1)->CreateA();
echo get_class($NewObj);
echo "<br>";
$NewObj=(new Factory2)->CreateB();
echo get_class($NewObj);
?>
输出:
ObjA1
ObjB2
同样,我们也可以针对接口和抽象来改写上面的代码,让编码有不同的呈现样式。
设计模式只是在特定环境下针对特定问题所产生的特定套路或者固定模式,只要掌握基本原则,那么也可以根据自己的情况灵活变通。
在上面的例子中,看到了简单工厂、工厂、抽象工厂,他们有差异。简单工厂和工厂模式涉及的子类都基于相同的基类或者接口,都是直接创建产品。抽象工厂模式涉及的子类基于不同的基类或者接口,先创建工厂,然后再由工厂创建产品。
关键在于职责划分,为什么要抽象?因为剥离出来共同点,这样有助于设计的稳定。
比如多系列的产品也可以使用简单工厂的模式进行,不过是Switch的语句多一些而已。
关键就是对象的创建和使用分离。
也可以根据产品的名称来创建,用户只要知道产品名称即可。
<?php
interface IShow{
function show();
}
class BaseObjA implements IShow{
protected static $Name="BaseObjA";
function show(){
echo self::$Name."<br>";
}
}
class BaseObjB implements IShow{
protected static $Name="BaseObjB";
function show(){
echo self::$Name."<br>";
}
}
class ObjA1 extends BaseObjA{
function __construct(){
self::$Name=parent::$Name." => 1";
}
}
class ObjA2 extends BaseObjA{
function __construct(){
self::$Name=parent::$Name." => 2";
}
}
class ObjB1 extends BaseObjB{
function __construct(){
self::$Name=parent::$Name." => 1";
}
}
class ObjB2 extends BaseObjB{
function __construct(){
self::$Name=parent::$Name." => 2";
}
}
class simpleFactory{
protected static $ObjList=['ObjA1','ObjA2','ObjB1','ObjB2'];
public static function GetObjByName($ObjName){
if( in_array($ObjName, self::$ObjList) ){
return new $ObjName;
}else{
return null;
}
}
}
//创建对象ObjA1
$NewObj=simpleFactory::GetObjByName("ObjA1");
if($NewObj){
$NewObj->show();
}else{
echo "无法生成此对象";
}
//创建对象ObjB1
$NewObj=simpleFactory::GetObjByName("ObjB2");
if($NewObj){
$NewObj->show();
}else{
echo "无法生成此对象";
}
//创建对象ObjC2,不存在!
$NewObj=simpleFactory::GetObjByName("ObjC2");
if($NewObj){
$NewObj->show();
}else{
echo "无法生成此对象";
}
?>
输出:
BaseObjA => 1
BaseObjB => 2
无法生成此对象
不同的开发语言在应用设计模式上有一些实现细节方面的差异和变化。理解和掌握其中的思想和规则,对于我们在编码过程中写出高质量的优雅代码还是有明显益处的。