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

场景: 组装电脑。
    需要做的工作:
        选择所有配件,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. 容易造成层次复杂

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

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

何时选用抽象工厂模式:
    























  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值