/**
* 1.3 抽象工厂模式
* 解决的问题:
* 如何解决多个类实例化对象的问题。
* 解决的方案:
* 提供一个创建一系列相关或相互依赖对象的
* 接口,而无需指定它们具体的类。
* 该模式包含四种角色:
* 1. 抽象产品角色(两个或多个)
* 职责:同工厂方法模式
* 2. 具体产品角色
* 职责:同工厂方法模式
* 3. 抽象工厂角色
* 职责:同工厂方法模式
* 4. 具体工厂角色
* 职责:同工厂方法模式
* 优点:
* 1. 易于交换产品系列,由于工厂类在
* 一个应用中只需要在初始化的时候
* 出现一次,这就使得改变一个应用
* 的具体工厂变得非常容易,它只需
* 要改变具体工厂即可使用不同的产
* 品配置。
* 2. 使具体的创建实例过程与客户端分
* 离,客户端时通过它们的抽象接口
* 操纵实例,产品的具体类名也被具
* 体工厂的实现分离,不会出现在客
* 户代码中。
* 缺点:
* 1. 当增加新的产品时,就要增加抽象
* 产品角色、具体产品角色、具体工
* 厂角色三个角色(类),另外至少
* 还要修改抽象工厂角色。
* 2. 在客户端很多的话,如果要进行产
* 品的切换,那么就会出现大批量的
* 改动。
* 使用场景:
* 1. 一个系统要独立于它的产品的创建
* 、组合和表示时。
* 2. 一个系统要由多个产品系列中的一
* 个来配置时(比如数据库)。
* 3. 当你要强调一系列相关产品对象的
* 设计以便进行联合使用时。
* 4. 当你提供一个产品类库,而只想显
* 示它们的接口而不是实现时。
*
*/
/**
* 以两种数据库产品来举例
*/
//第一种抽象产品类
abstract class User{
abstract public function addUser();
abstract public function queryUser();
}
//第二种抽象产品类
abstract class Department{
abstract public function addDeptmt();
abstract public function queryDeptmt();
}
/**
* 第三种抽象产品类
* .
* .
* .
* .
* 第N种抽象产品类
*/
//第一种抽象产品类的具体产品类
//用户的添加和查询
//MysqlUser是抽象产品User的第一个具体产品类
class MysqlUser extends User{
public function addUser(){
echo '在Mysql数据库中添加一个用户';
}
public function queryUser(){
echo '在Mysql数据库中查询某个用户信息';
}
}
//MongodbUser是抽象产品User的第二个具体产品类
class MongodbUser extends User{
public function addUser(){
echo '在MongoDB数据库中添加一个新用户';
}
public function queryUser(){
echo '在MongoDB数据库中查询某个用户信息';
}
}
//第二种抽象产品类的具体产品类
//部门的添加和查询
//MysqlDeptmt是抽象产品Department的第一个具体产品类
class MysqlDeptmt extends Department{
public function addDeptmt(){
echo '在Mysql数据库中添加一个新部门';
}
public function queryDeptmt(){
echo '在Mysql数据库中查询某个部门信息';
}
}
//MongodbDeptmt是抽象产品Department的第二个具体产品类
class MongodbDeptmt extends Department{
public function addDeptmt(){
echo '在MongoDB数据库中添加一个新部门';
}
public function queryDeptmt(){
echo '在MongoDB数据库中查询部门信息';
}
}
//抽象工厂角色
abstract class DBFactry{
//因为是有两个抽象产品,多以与之对应的
//应该有两个创建响应产品对象的方法。
abstract static public function createUser();
abstract static public function createDept();
}
/**
* 具体工厂角色
* 每个抽象产品角色对应的具体产品角色都有
* 一个与之对应的具体工厂角色,也就是说抽
* 象产品对应多少个具体的产品,就有多少个
* 具体产品工厂角色与之对应。因为抽象工厂
* 方法对应的是多个产品,所以可以在具体工
* 厂中返回多个具体产品的实例对象。
*/
//MysqlDBFactry是与具体产品MysqlUser和
//MysqlDeptmt对应的具体工厂类。
class MysqlDBFactry extends DBFactry{
public static function createUser(){
return new MysqlUser();
}
public static function createDept(){
return new MysqlDeptmt();
}
}
//MongoDBFactry是与具体产品MongodbUser和
//MongoDeptmt对应的具体工厂类。
class MongoDBFactry extends DBFactry{
public static function createUser(){
return new MongodbUser();
}
public static function createDept(){
return new MongodbDeptmt();
}
}
/**
* 使用简单工厂改进抽象工厂
* 改进后的优点:
* 1. 当切换数据库时,客户端无需任何
* 修改。
* 缺点:
* 如果再新增一种数据库,那么就要添加
* 一个具体产品类,修改简单工厂中相关
* 的switch语句。
*
*/
class SimpleFactry{
//$db:作为数据库切换变量
private static $db='mysql';
public static function createUser(){
switch (self::$db) {
case 'mysql':
$obj=new MysqlUser();
break;
case 'mongodb':
$obj=new MongodbUser;
break;
}
return $obj;
}
public static function createDept(){
switch(self::$db){
case 'mysql':
$obj=new MysqlDeptmt();
break;
case 'mongodb':
$obj=new MongodbDeptmt();
break;
}
return $obj;
}
}
/**
* 利用反射技术进一步改进抽象工厂模式
*/
class ReflctSmplFactry{
private static $db='Mysql';
public static function createUser(){
$className=self::$db.'User';
$reflct=new ReflectionClass($className);
return $reflct->newInstance();
}
public static function createDept(){
$className=self::$db.'Deptmt';
$reflct=new ReflectionClass($className);
return $reflct->newInstance();
}
}
//正常抽象工厂模式的客户端
$factry=MysqlDBFactry::createDept();
$factry->addDeptmt();
$factry->queryDeptmt();
$f2=MongoDBFactry::createUser();
$f2->addUser();
$f2->queryUser();
// 使用简单工厂改进后的抽象工厂模式的客户端
$fcty=SimpleFactry::createUser();
$fcty->addUser();
$fcty->queryUser();
$fcty2=SimpleFactry::createDept();
$fcty2->addDeptmt();
$fcty2->queryDeptmt();
// 使用反射技术改进后的抽象工厂模式的客户端
$fctry=ReflctSmplFactry::createUser();
$fctry->addUser();
$fctry->queryUser();
$fctry2=ReflctSmplFactry::createDept();
$fctry2->addDeptmt();
$fctry2->queryDeptmt();
?>