【发布时间】:2016-01-03 11:51:59
【问题描述】:
通常我们使用工厂方法来处理创建对象的问题,而不必指定将要创建的对象的确切类。
假设我们有 5 种不同的记录器实现。以下是如何使用传统工厂方法实现的伪代码:
class LoggerFactoryMethod extends AbstractFactoryMethod {
function makeLogger($param) {
$logger = NULL;
switch ($param) {
case "mysql":
$logger = new MysqlLogger;
break;
case "mongo":
$logger = new MongoLogger;
break;
case "txt":
$logger = new TxtLogger;
break;
case "redis":
$logger = new RedisLogger;
break;
case "memcached":
$logger = new MemcachedLogger;
break;
default:
$logger = new TxtLogger;
break;
}
return $logger;
}
这很好用,但是有许多 if/else(或 switch/code)条件并不那么酷。假设明天我们想再添加一个实现。我们将需要修改此代码并添加新的案例条件。这样,我们可能会打破 SOLID 原则中的 Open/Closed 原则。
相反,使用反射 API 更优雅,并且不需要对新实现进行重大更改。使用反射 API 的相同示例是:
class LoggerFactoryMethod extends AbstractFactoryMethod {
function makeLogger($param) {
$allowed_implementations = array('mysql','mongo', 'txt', 'redis' , 'memcached');
$class = new ReflectionClass($param);
if (!in_array($param, $allowed_implementations) || !($class->IsInstantiable())){
return null;
}
return $class->newInstance();
}
使用反射 API 代替传统的工厂模式(使用 if/else 条件)有什么缺点吗?使用它是一种好习惯吗?
【问题讨论】:
-
我不会说 PHP,但是“一般来说”(其他语言,反射通常比构造函数更昂贵,所以你会受到资源开销)另外你实际上是在限制你的工厂模式, 因为你假设构造函数都是无操作的,如果你有一些操作数,那么你将需要逻辑来启用它。一般来说,工厂有很长的 if/then/else 或某种动态绑定列表,但 if/then 或 switch stmt 通常更易于处理+更快且更易于调试(以更多物理代码为代价)所以(忽略任何 PHP 都需要权衡 '?')
-
我同意@mawalker 并且更喜欢传统的开关实现。当您想解决简单条件时,简单的条件语句没有错。由于 $allowed_implementations 而添加新的记录器实现时,您建议的改进工厂方法也需要修改。
-
正如@iluwatar 指出的那样,如果您想变得更加灵活并支付反射成本,只需提取
$allowed_implementations集合,以便将其配置为系统/应用程序属性,所以你的工厂总能找到它。 -
1.不确定 PHP 的反射是否过于昂贵,因为它是解释性语言。它可以比编译语言更容易(更便宜)进行反射。 2. 反射不需要 $allowed_implementations。如果我们可能想做一些过滤,这只是作为示例。
标签: php oop design-patterns reflection factory