创建模式:“Bastard Factory”,抽象工厂的衍生品

发布于 2024-09-11 22:50:42 字数 1540 浏览 1 评论 0原文

我目前正在尝试找出在当前的 PHP 5.2 项目上创建对象的最佳方法。我基本上有一个通过键返回对象的注册表。如果注册表没有具有指定键的对象,它将尝试通过调用通过构造提供给注册表的工厂方法来创建一个对象。看下面的代码来验证:

interface IFactory
{
    public function createProduct( $key );
}

class Registry
{
    private $m_elements = array( );
    private $m_factory;
    public function __construct( IFactory $factory )
    {
       $this->m_factory = $factory;
    }
    public function getElement( $key )
    {
      if ( !array_key_exists( $key, $this->m_elements ) )
      {
          $this->m_elements[$key] = $this->m_factory->createProduct( $key );
      }
      return $this->m_elements[$key];
    }
}

因为我有不同类别的对象,我想存储在不同的注册表中,所以我将注册表对象包装到每个类别的单例中,如下所示:

class SpecialRegistry
{
   private static $instance = null;

   public static function getInstance( )
   {
       if( self::$instance === null )
       {
           self::$instance = new Registry( new SpecialFactory( ) );
       }
       return self::$instance;
   }
}

我的 Special 类相当复杂且很大,有很多不同属性和组合对象。因为我不想将我的 Special 类绑定到任何特定的后端,所以我将为每个不同的后端(例如 MySQL 数据库或文件流)设置不同的工厂。所以我会将加载和初始化逻辑移至工厂。然而,只有当特殊类中的所有字段对工厂都是公开的时,这才有效。然而,它们不应该对应用程序的其余部分公开。

在 C++ 中,我可以使用朋友来规避这个问题。 另外,在堆栈溢出上,我读到了几乎相同的主题,但适用于 C#。它说我应该简单地将 Special 类中的所有字段设置为 public,并让 Factory 仅返回一个接口,该接口公开我想要向应用程序公开的方法和属性。但由于 PHP 不支持返回类型提示,我无法仅返回 Special 类实现的接口。 我想出的另一种方法是实际上让 SpecialFactory 继承 Special 类,从而可以从工厂访问私有和受保护的字段。这就是我所说的“Bastard Factory”,因为工厂继承了它自己的产品。

我想知道你们中是否有人能想出更好的方法来实现我想要的。或者我是否完全偏离了轨道,将初始化过程交给工厂是绝对不行的?我很好奇你的意见!

I am currently trying to figure out what the best way is to create my objects on my current PHP 5.2 project. I basicly have a Registry which returns objects by keys. If the Registry does not have an object with the specified key it will try to create one by calling a factory method that is supplied to the registry by construction. Look at the following code to calrify:

interface IFactory
{
    public function createProduct( $key );
}

class Registry
{
    private $m_elements = array( );
    private $m_factory;
    public function __construct( IFactory $factory )
    {
       $this->m_factory = $factory;
    }
    public function getElement( $key )
    {
      if ( !array_key_exists( $key, $this->m_elements ) )
      {
          $this->m_elements[$key] = $this->m_factory->createProduct( $key );
      }
      return $this->m_elements[$key];
    }
}

Because I have different of categories of objects I'd like to store in different registries I wrap a Registry oject into a singleton for each category, like this:

class SpecialRegistry
{
   private static $instance = null;

   public static function getInstance( )
   {
       if( self::$instance === null )
       {
           self::$instance = new Registry( new SpecialFactory( ) );
       }
       return self::$instance;
   }
}

My Special class is rather complex and big with alot of different attributes and composition objects. Because I do not want to bind my Special class to any specific backend I was going to have different Factories for each different backend (eg MySQL database or file stream). So I would move the loading and initialization logic to the Factories. This however will only work if all fields in the Special class are public to the Factory. They shouldn't however be public to the rest of the application.

In C++ I could use friends to circumvent this problem.
Also here on stack overflow I read on nearly the same topic, but applied to C#. It said I should simply set all fields public in the Special class and have the Factory only return an Interface that exposes the methods and attributes I want to be public to the application. But since PHP does not support return type hinting I am not able to return only an interface that the Special class implements.
Another way I came up with would be to actually have the SpecialFactory inherit from the Special class making it possible to access private and protected fields from the factory. This is what I called "Bastard Factory" since the factory inherits from it's own product.

I'd wish to know if anyone of you guys can come up with a better way of achieving what I want. Or am I completely off track and yielding the initialization process to the factory is an absolute no-go? I'm curious on your opinions!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

染柒℉ 2024-09-18 22:50:42

来自 Java 背景,在其中添加一个构建器怎么样?该构建器可以通过工厂可以在其上构建的公共字段来公开其状态。构建器完成后,将其传递给您的 Special 类并让它从构建器加载其状态。

在你的工厂中是这样的(伪代码):

public function createProduct() {
  SpecialBuilder builder = new SpecialBuilder();
  // Do whatever you would have done to the Special class to the builder
  // ...
  Special special = new Special(builder);
  return special;
}

通过这种方式,你的特殊对象仍然可以隐藏其内部状态。我看到的唯一真正的缺点是它是一个轻微的对象过载情况。

Coming from a Java background, how about adding a builder in there? This builder could expose its state via public fields which the factory can construct on. Once the builder is complete, pass it to your Special class and let it load its state from the builder.

Something like this in your factory (pseudocode):

public function createProduct() {
  SpecialBuilder builder = new SpecialBuilder();
  // Do whatever you would have done to the Special class to the builder
  // ...
  Special special = new Special(builder);
  return special;
}

In this way your Special object can still hide its internal state. The only real disadvantage I see is that it's a slight case of object overload.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文