PHP 抽象工厂模式实现
PHP Abstract Factory Pattern Implementation
我正在阅读有关可用的不同模式的信息。目前我正在研究抽象工厂模式,我认为我对它有很好的把握。除了维基百科,我的资源是:
http://www.tutorialspoint.com/design_pattern/abstract_factory_pattern.htm
http://www.oodesign.com/abstract-factory-pattern.html
https://github.com/domnikl/DesignPatternsPHP/tree/master/Creational/AbstractFactory
我正在使用 Apple 及其产品制作示例抽象工厂模式作为示例。我知道代码重复是糟糕的设计,因此我写这篇文章的原因。到目前为止我的代码是:
abstract class AbstractAppleFactory {
abstract public function createiPod( $capacity, $type, $color, $engraving );
abstract public function createiPhone( $capacity, $type, $color, $antenna );
abstract public function createComputer( $type, $HDCapacity, $CPU, $ram );
}
class iPodFactory extends AbstractAppleFactory {
public function createiPod( $capacity, $type, $color, $engraving ) {
$class = 'iPod' . $type;
return new $class( $capacity, $color, $engraving);
}
public function createiPhone( $capacity, $type, $color, $antenna ){ /* no implementation necessary */}
public function createComputer( $type, $HDCapacity, $CPU, $ram ){ /* no implementation necessary */}
}
interface iPlayer {
public function play();
public function stop();
public function fastForward();
public function rewind();
}
abstract class iPod implements iPlayer {
protected $capacity;
protected $color;
protected $engraving;
public function __construct( $capacity, $color, $engraving = null ) {
$this->capacity = $capacity;
$this->color = $color;
$this->engraving = $engraving;
}
}
class iPodClassic extends iPod {
public function play() {/* implementation goes here */}
public function stop() {/* implementation goes here */}
public function fastForward() {/* implementation goes here */}
public function rewind() {/* implementation goes here */}
}
class iPodShuffle extends iPod {
public function play() {/* implementation goes here */}
public function stop() {/* implementation goes here */}
public function fastForward() {/* implementation goes here */}
public function rewind() {/* implementation goes here */}
}
等等等。这里要放的代码太多了。我知道最好在目录和名称空间中进行组织。那不是我现在正在学习的。我正在学习模式和 OOP 概念。
相关部分是:
class iPodFactory extends AbstractAppleFactory {
public function createiPod( $capacity, $type, $color, $engraving ) {
$class = 'iPod' . $type;
return new $class( $capacity, $color, $engraving);
}
public function createiPhone( $capacity, $type, $color, $antenna ){ /* no implementation necessary */}
public function createComputer( $type, $HDCapacity, $CPU, $ram ){ /* no implementation necessary */}
}
由于inheritance/abstraction,我不得不在一个不相关的工厂中实现两个不必要的方法。 createiPhone()
和 createComputer()
。我在做抽象工厂模式吗?同样,"code duplication is bad design!"有什么更好的方法来解决这个问题?
你的方法是对的,但我认为你的接口是错误的。
首先,不要使用 abstract
class 除非您需要创建一个将在子 classes 上使用的方法。使用interface
会更好。
这将是我的解决方案:
<?php
interface AppleFactoryInterface
{
function create($data);
}
这是一个 iPhoneFactory:
<?php
class iPhoneFactory implements AppleFactoryInterface
{
public function create($data)
{
$klass = sprintf('iPhone'.$data['type']);
$instance = new $klass;
$instance->setFromArray($data);
return $instance;
}
}
如您所见,我的代码更少,更容易理解。
我认为你犯了一个重大错误。抽象工厂的目的是为创建产品系列创建抽象,因此您可以轻松地将其更改为不同的系列。
f.e。苹果 => 三星 :)
interface ComputerAbstractFactory {
/**
* @return Tablet
*/
function createTablet();
/**
* @return Phone
*/
function createPhone();
/**
* @return Computer
*/
function createComputer();
}
class AppleComputerFactory implements ComputerAbstractFactory {}
class SamsungComputerFactory implements ComputerAbstractFactory {}
class IPad implements Tablet {}
class GalaxyTab implements Tablet {}
...
当您想在两家公司之间切换时,使用抽象工厂模式很有意义。
您的代码应该仅依赖于抽象(SOLID 原则)ComputerAbstractFactory、Tablet、Phone、Computer。
这样,如果您决定(f.e。通过一些配置开关)应该使用哪个制造商,那么您将选择的 ComputerAbstractFactory 实现注入到您的业务中就足够了
代码,你就完成了——一切正常,平板电脑、手机等都创建好了
您需要决定要在应用程序中创建什么抽象,以便调用代码不会耦合到该抽象的具体实现。我相信 IPlayer 是您想要的,其中 IPodClassic IPodShuffle 是具体实现。
如果我是对的,你应该创建 IPlayerFactory
class IPlayerFactory {
/**
* @return IPlayer
*/
function create() {...}
}
关于你提到的重复。如果 iPodFactory 扩展 AbstractAppleFactory 它应该实现它的所有方法(顺便说一句,如果 AbstractAppleFactory 没有任何实现它应该是一个接口)
你从 SOLID 原则中打破了 Liskov 原则。简短版本 - 如果调用代码依赖于 AbstractAppleFactory 并且它将 iPodFactory 作为具体实现进行操作,它将在调用 createiPhone 或 createComputer 时中断 - 因此在这种情况下抽象不起作用。
我正在阅读有关可用的不同模式的信息。目前我正在研究抽象工厂模式,我认为我对它有很好的把握。除了维基百科,我的资源是: http://www.tutorialspoint.com/design_pattern/abstract_factory_pattern.htm http://www.oodesign.com/abstract-factory-pattern.html https://github.com/domnikl/DesignPatternsPHP/tree/master/Creational/AbstractFactory
我正在使用 Apple 及其产品制作示例抽象工厂模式作为示例。我知道代码重复是糟糕的设计,因此我写这篇文章的原因。到目前为止我的代码是:
abstract class AbstractAppleFactory {
abstract public function createiPod( $capacity, $type, $color, $engraving );
abstract public function createiPhone( $capacity, $type, $color, $antenna );
abstract public function createComputer( $type, $HDCapacity, $CPU, $ram );
}
class iPodFactory extends AbstractAppleFactory {
public function createiPod( $capacity, $type, $color, $engraving ) {
$class = 'iPod' . $type;
return new $class( $capacity, $color, $engraving);
}
public function createiPhone( $capacity, $type, $color, $antenna ){ /* no implementation necessary */}
public function createComputer( $type, $HDCapacity, $CPU, $ram ){ /* no implementation necessary */}
}
interface iPlayer {
public function play();
public function stop();
public function fastForward();
public function rewind();
}
abstract class iPod implements iPlayer {
protected $capacity;
protected $color;
protected $engraving;
public function __construct( $capacity, $color, $engraving = null ) {
$this->capacity = $capacity;
$this->color = $color;
$this->engraving = $engraving;
}
}
class iPodClassic extends iPod {
public function play() {/* implementation goes here */}
public function stop() {/* implementation goes here */}
public function fastForward() {/* implementation goes here */}
public function rewind() {/* implementation goes here */}
}
class iPodShuffle extends iPod {
public function play() {/* implementation goes here */}
public function stop() {/* implementation goes here */}
public function fastForward() {/* implementation goes here */}
public function rewind() {/* implementation goes here */}
}
等等等。这里要放的代码太多了。我知道最好在目录和名称空间中进行组织。那不是我现在正在学习的。我正在学习模式和 OOP 概念。
相关部分是:
class iPodFactory extends AbstractAppleFactory {
public function createiPod( $capacity, $type, $color, $engraving ) {
$class = 'iPod' . $type;
return new $class( $capacity, $color, $engraving);
}
public function createiPhone( $capacity, $type, $color, $antenna ){ /* no implementation necessary */}
public function createComputer( $type, $HDCapacity, $CPU, $ram ){ /* no implementation necessary */}
}
由于inheritance/abstraction,我不得不在一个不相关的工厂中实现两个不必要的方法。 createiPhone()
和 createComputer()
。我在做抽象工厂模式吗?同样,"code duplication is bad design!"有什么更好的方法来解决这个问题?
你的方法是对的,但我认为你的接口是错误的。
首先,不要使用 abstract
class 除非您需要创建一个将在子 classes 上使用的方法。使用interface
会更好。
这将是我的解决方案:
<?php
interface AppleFactoryInterface
{
function create($data);
}
这是一个 iPhoneFactory:
<?php
class iPhoneFactory implements AppleFactoryInterface
{
public function create($data)
{
$klass = sprintf('iPhone'.$data['type']);
$instance = new $klass;
$instance->setFromArray($data);
return $instance;
}
}
如您所见,我的代码更少,更容易理解。
我认为你犯了一个重大错误。抽象工厂的目的是为创建产品系列创建抽象,因此您可以轻松地将其更改为不同的系列。 f.e。苹果 => 三星 :)
interface ComputerAbstractFactory {
/**
* @return Tablet
*/
function createTablet();
/**
* @return Phone
*/
function createPhone();
/**
* @return Computer
*/
function createComputer();
}
class AppleComputerFactory implements ComputerAbstractFactory {}
class SamsungComputerFactory implements ComputerAbstractFactory {}
class IPad implements Tablet {}
class GalaxyTab implements Tablet {}
...
当您想在两家公司之间切换时,使用抽象工厂模式很有意义。 您的代码应该仅依赖于抽象(SOLID 原则)ComputerAbstractFactory、Tablet、Phone、Computer。 这样,如果您决定(f.e。通过一些配置开关)应该使用哪个制造商,那么您将选择的 ComputerAbstractFactory 实现注入到您的业务中就足够了 代码,你就完成了——一切正常,平板电脑、手机等都创建好了
您需要决定要在应用程序中创建什么抽象,以便调用代码不会耦合到该抽象的具体实现。我相信 IPlayer 是您想要的,其中 IPodClassic IPodShuffle 是具体实现。 如果我是对的,你应该创建 IPlayerFactory
class IPlayerFactory {
/**
* @return IPlayer
*/
function create() {...}
}
关于你提到的重复。如果 iPodFactory 扩展 AbstractAppleFactory 它应该实现它的所有方法(顺便说一句,如果 AbstractAppleFactory 没有任何实现它应该是一个接口) 你从 SOLID 原则中打破了 Liskov 原则。简短版本 - 如果调用代码依赖于 AbstractAppleFactory 并且它将 iPodFactory 作为具体实现进行操作,它将在调用 createiPhone 或 createComputer 时中断 - 因此在这种情况下抽象不起作用。