您的位置:首页 > 编程语言 > PHP开发

PHP设计模式——抽象工厂(研磨设计模式学习笔记)

2012-11-11 00:55 537 查看
场景: 组装电脑。
    需要做的工作:
        选择所有配件,CPU,主板,显卡,内存,电源等。为了简单只选择CPU,和主板的问题。
        CPU :属性有品牌,型号,针脚,确定了这些才能确定具体的CPU

        主板:属性有品牌,芯片组等。也只有这些确定了,才能确定具体的主板。

        需要考虑各个配件之间的兼容性。cpu针角与主板提供的针角是否兼容。

            装机工程师只装机,而客户负责选择配件。

不用模式的装机方案:(还是用到的简单工厂)

interface CPUApi {
public function calculate();
}

interface MainboardApi {
public function installCPU();
}

class IntelCPU implements CPUApi {
private $pins = 0;

public function __construct($pins) {
$this->pins = $pins;
}

public function calculate() {
echo 'now in Inter CPU, pins='.$this->pins;
}
}

class AMDCPU implements CPUApi {
private $pins = 0;

public function __construct($pins) {
$this->pins = $pins;
}

public function calculate() {
echo 'now in AMD CPU, pins='.$this->pins;
}
}

class GAMainboard implements MainboardApi {
private $cpuHoles = 0;

public function __construct($cpuHoles) {
$this->$puHoles = $cpuHoles;
}

public function installCPU() {
echo 'now in GAMainboard cpuHoles=' + $this->cpuHoles;
}
}

class MSIMainboard implements MainboardApi {
private $cpuHoles = 0;

public function __construct($cpuHoles) {
$this->$puHoles = $cpuHoles;
}

public function installCPU() {
echo 'now in MSIMainboard cpuHoles=' + $this->cpuHoles;
}
}

class CPUFactory {
public static function createCPUApi($type) {
switch($type) {
case '1':
$cpu = new GAMainboard(1156);
break;
case '2':
$cpu = new AMDCPU(939);
break;
}
return $cpu;
}
}

class MainboardFactory {
public static function createMainboardApi($type) {
switch($type) {
case '1':
$mainbord = new IntelCPU(1156);
break;
case '2':
$mainbord = new MSIMainboard(939);
break;
}
return $mainbord;
}
}

class ComputerEngineer {
private $cpu = null;
private $mainboard = null;

public function makeComputer($CPUApi, $Mainboard) {
//1 准备硬件
$this->prepareHardwares($CPUApi, $Mainboard);
//2 组装机器
//3 测试
//4 交付客户
}

public function prepareHardwares($cpuType, $mainboardType) {
$this->cpu = CPUFactory::createCPUApi($cpuType);
$this->mainboard = MainboardFactory::createMainboardApi($mainboardType);

$this->cpu->calculate();
$this->mainboard->installCPU();
}
}

class Client {
public static function main() {
$engineer = new ComputerEngineer();
$engineer->makeComputer(1,1);
}
}


上面的实现是有些问题:
    1. CPU与主板是有关系的,需要相互匹配。
    2. 只知道所需对象的接口,只不知道其具体实现,或是不知道具体使用那一个。

但上面的实现方案,是无法解决这个问题。工厂方法和简单工厂只关注单个产品的创建,CPU工厂只关注CPU,主板工厂只关注主板。这里要解决的问题是要创建一系列的产品对象,而这系列对象是构建新的对象所需要的组成部分,这一列的对象相互之间是有约束的。

解决方案:使用抽象工厂模式来解决问题;

抽象工厂模式
定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们的具体实现类。

// 对以上代码进行改造,加入抽象工厂的定义

interface AbstractFactory {
public function createCPUApi();
public function createMainboard();
}

class Schema1 implements AbstractFactory {
public function createCPUApi() {
return new IntelCPU(1156);
}

public function createMainboard() {
return new GAMainboard(1156);
}
}

class Schema2 implements AbstractFactory {
public function createCPUApi() {
return new AMDCPU(939);
}

public function createMainboard() {
return new MSIMainboard(939);
}
}

//修改工程师类
class ComputerEngineer2 {
private $cpu = null;
private $mainboard = null;

public function makeComputer(AbstractFactory $schema){
$this->prepareHardwares($schema);
}

public function prepareHardwares(AbstractFactory $schema){
$this->cpu = $schema->createCPUApi();
$this->mainboard = $schema->createMainboard();

$this->cpu->calculate();
$this->mainboard->installCPU();
}
}

class Client2 {
public static function main() {
$engineer = new ComputerEngineer();
$schema   = new Schema1();
$engineer->makeComputer($schema);
}
}


模式讲解:

功能:为一系列相关对象或相互依赖的对象创建一个接口。需要注意的是这个接口内的方法不是随意堆砌的,而是一系列相关或相互依赖的方法。从某种意义上讲,抽象工厂是现代战争产品系列。

实现成接口:AbstractFactory 通常为接口,不要被名字误导,以为是抽象类。当然如果提供公共的功能,也未偿不可,但一般不这样做。

使用工厂方法:AbstractFactory 定义了创建产品所需要的接口,具体的实现是在实现类里面,通常在实现类里面就需要多种更具体的实现。所以AbstractFactory定义的创建产品的方法可以看成是工厂方法,而这些工厂方法的具体实现延迟到了具体的工厂里面,也就是说使用工厂方法来实现抽象工厂。

切换产品:抽象工厂定义的一系列对象是相互关联的,这些产品就构成了产品簇,也就是抽象工厂定义了一个产品簇。切换产品簇时,就只要提供一个不同的抽象工厂实现就可以了。

抽象工厂模式的调用顺序:

1. 客户端 创建具体工厂

2. 工厂创建产品A,B。

3. AB分别调用A,B方法。

可扩展的工厂:
    当前如果要增加内存时,就需要在抽象工厂方法里面创建添加内存的方法。当抽象工厂发生改变所有的具体实现都要发生改变。如上不灵活。

    改进方式:抽象工厂只需要一个方法,给这个方法一个参数,通过这个参数来判断具体要创建什么产品对象,由于只有一个方法,所以返回类型不在是具体的一个产品了,只是能所有产品都继承或实现的一个类型。

    改造抽象工厂:

//继承改造上面的不灵活

interface AbstractFactory2 {
public function createProduct($type);
}

class Schema2_1 implements AbstractFactory2 {
public function createProduct($type) {
$object = null;
switch($type) {
case '1':
$object =  new IntelCPU(1156);
break;
case '2':
$object = new GAMainboard(1156);
break;
}
return $object;
}
}

class Schema2_2 implements AbstractFactory2 {
public function createProduct($type) {
$object = null;
switch($type) {
case '1':
$object = new AMDCPU(939);
break;
case '2':
$object =  new MSIMainboard(939);
break;
}
return $object;
}
}

class ComputerEngineer3 {
private $cpu = null;
private $mainboard = null;

public function makeComputer(AbstractFactory2 $schema){
$this->prepareHardwares($schema);
}

public function prepareHardwares(AbstractFactory2 $schema){
$this->cpu = $schema->createProduct(1);
$this->mainboard = $schema->createProduct(2);

$this->cpu->calculate();
$this->mainboard->installCPU();
}
}

//体现以上试带来的灵活,增加新产品,内存

interface MemoryApi {
function cacheData();
}

class HyMemory implements MemoryApi {
public function cacheData() {
echo '正在使用现代内存';
}
}

class Schema2_3 implements AbstractFactory2 {
public function createProduct($type) {
$object = null;
switch($type) {
case '1':
$object =  new IntelCPU(1156);
break;
case '2':
$object = new GAMainboard(1156);
break;
case '3':
$object = new HyMemory();
break;
}
return $object;
}
}

class ComputerEngineer4 {
private $cpu = null;
private $mainboard = null;

private $memory = null;

public function makeComputer(AbstractFactory2 $schema){
$this->prepareHardwares($schema);
}

public function prepareHardwares(AbstractFactory2 $schema){
$this->cpu = $schema->createProduct(1);
$this->mainboard = $schema->createProduct(2);
$this->memory = $schema->createProduct(3);

$this->cpu->calculate();
$this->mainboard->installCPU();
$this->memory->cacheData();
}
}

class Client3 {
public static function main() {
$engineer = new ComputerEngineer();
$schema   = new Schema2_3();
$engineer->makeComputer($schema);
}
}


抽象工厂模式和DAO

优点:
    1. 分享接口与实现

    2. 使得切换产品簇变得容易

缺点:
    1. 不太容易扩展新产品

    2. 容易造成层次复杂

抽象工厂的本质:
    选择产品簇的实现。定义在抽象工厂里面的方法通常是有联系的,它们都是产品的某一部分,或者是相互依    赖的。如果只定义一个方法,直接创建产品,则就退化成了工厂方法了。

工厂方法的本质:
    选择单个产品的实现。虽然一个类里可以有多个工厂方法,但这些方法之间是没有联系的。

何时选用抽象工厂模式:
    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  PHP 设计模式