首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >允许使用PHP中的抽象工厂模式进行自定义类实例化

允许使用PHP中的抽象工厂模式进行自定义类实例化
EN

Stack Overflow用户
提问于 2012-02-10 00:13:21
回答 3查看 413关注 0票数 2

目前,我使用抽象工厂来允许为生成请求对象指定自定义类名。我这样做的理由是允许我在不修改代码的情况下轻松地扩展核心功能。然而,最近,我对这种方法的有效性产生了一些怀疑。所以我的问题是:

允许工厂实例化,任何符合预期接口的提交的类名都是工厂概念的私生子化吗?为了避免这种情况,我会得到更好的服务吗?

更新

这里的逻辑是这样的:一方面,一个真实的汽车工厂(例如)如果没有配备制造这类汽车的机器,就不能创造出一辆汽车。另一方面,下面的代码就像给了同一家汽车工厂一个蓝图,使它原本不打算生产的定制汽车。

另一种方法是传入配置对象,指定可与工厂一起使用的自定义类名,并将工厂限制为只生成自定义类,如果它与配置指定的自定义类名具体匹配的话。有什么想法吗?

相关的密码..。

代码语言:javascript
复制
<?php

interface AbstractRequestFactory
{
  public function buildRequest($type);
}

class RequestFactory implements AbstractRequestFactory
{
  public function buildRequest($type='http')
  {
    if ($type == 'http') {
      return new HttpRequest();
    } elseif ($type == 'cli') {
      return new CliRequest();
    } elseif ($custom = $this->makeCustom($type)){
      return $custom;
    } else {
      throw new Exception("Invalid request type: $type");
    }
  }

  protected function makeCustom($type)
  {
    if (class_exists($type, FALSE)) {
      $custom = new $type;
      return $custom instanceof RequestInterface ? $custom : FALSE;
    } else {
      return FALSE;
    }
  }
}

// so using the factory to create a custom request would look like this:

class SpecialRequest implements RequestInterface {}

$factory = new RequestFactory();
$request = $factory->buildRequest('\SpecialRequest');
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-02-10 00:53:50

你的东西看上去很不错。拥有一个工厂的目的是传递一些条件,并让该方法返回一个对象,假设该对象具有调用代码可用的相同的可调用方法。您是通过实现RequestInterface来执行这个假设的,因此只要任何自定义请求类都实现相同的接口,就不会出现“无法在非对象上调用函数”的场景。

有几项建议(只是个人偏好):

bool)

  • Depending
  • I将在buildRequest
  • 中使用$type上的switch / case,我将从makeCustom()返回null或object,否则您将混合返回类型(object和case关于您有多少自定义类型,我实际上会将它们硬编码到开关情况中,以缓解任何混淆。不要误会我的意思,如果你有很多类的话,你所拥有的是伟大的,但很可能你没有。
  • 你有没有考虑过把“在不改变代码的情况下很容易扩展核心功能”的部分放入一个抽象的父类中,这个类可以通过自定义类型类来扩展?
  • ,因为工厂创建对象,所以通常将其设置为静态的。

示例代码片段:

代码语言:javascript
复制
public static function getRequest($type='http')
{
    switch ($type) {

        case 'http':
            return new HttpRequest();

        case 'cli':
            return new CliRequest();

        case 'myCustom1':
            return new MyCustom1();

        case 'myCustom2':
            return new MyCustom2();

        default: 
            throw new Exception("Invalid request type: $type");
    }
}

$request = RequestFactory::getRequest($type);

// As long as all objects in factory have access to same methods
$request->doSomething();
$request->andDoSomethingElse();

// Otherwise you end up with that feared 'unable to call function on non-object'
$request->iAmASneakyMethodNotEnforcedByAnInterfaceOrAvailableByExtension();    
票数 1
EN

Stack Overflow用户

发布于 2012-02-10 00:41:26

这是相当主观的,因此以下只是一个观点:

我不会很快用这样的东西。如果您只有少数几个工厂会关心的类,那么我只需要对它们进行硬编码。但如果你有大量的这些,我认为这是合适的。

考虑到您正在验证类是否扩展了适当的接口,我想说的是,您所做的工作没有什么问题,因为它是故障安全的。使用工厂方法的代码看起来是干净的,我认为这是最重要的事情。

如果你在各地使用这样的技术,那么我会反对它。但是,由于这是隐藏在实现中的,我认为您可以在做一些稍微不合适的事情时有更多的回旋余地。

票数 1
EN

Stack Overflow用户

发布于 2012-02-10 01:02:06

为什么不使用调度数组呢?即

代码语言:javascript
复制
class RequestFactory 
{
    private static $requests = array(
      'http' => 'HttpRequest',
      'cli' => 'CliRequest',
      'summatelse' => 'Summat'
    );
    public static GetRequest($type)
    {
       if (array_key_exists($type, $requests)) return new $requests[$type];
       else throw new Exception("Invalid request type: $type"); 
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9220939

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档