【问题标题】:Real world examples of Factory Method pattern工厂方法模式的真实示例
【发布时间】:2011-01-24 01:47:25
【问题描述】:

我刚刚阅读了工厂方法。我知道它提供了一种将实例化委托给子类的方法。但我无法理解在现实场景中的可能用途。

谁能举一个典型的例子来说明如何使用工厂方法模式,以便我可以与我所读的内容联系起来。

工厂方法模式是最佳解决方案的问题陈述足以说明问题。

【问题讨论】:

    标签: design-patterns factory-pattern


    【解决方案1】:

    实现工厂设计模式的类充当多个类之间的桥梁。考虑一个使用多个数据库服务器(如 SQL Server 和 Oracle)的示例。如果您正在使用 SQL Server 数据库作为后端开发应用程序,但将来需要将后端数据库更改为 oracle,如果您尚未按照工厂设计模式编写代码,则需要修改所有代码。

    在工厂设计模式中,您只需做很少的工作即可实现这一目标。实现工厂设计模式的类会照顾您并减轻您的负担。从数据库服务器切换根本不会打扰您。您只需要在配置文件中进行一些小改动。

    【讨论】:

    • 以上示例代码目前不可用。所以我发现这个链接及其有用.. primaryobjects.com/CMS/Article81.aspx
    • 为什么不直接使用通用接口和依赖注入呢?例如IDatabase 在 DI 可以很好地处理它的情况下,工厂模式似乎有点矫枉过正。
    • @LeviFuller 我想你可以,但至少在链接中的示例中,你不能将例如连接字符串添加到接口
    • @cah1r 也可以使用resolver来解决同一个接口有多个依赖的问题,或者不同的连接使用单独的接口
    【解决方案2】:

    带有静态创建的示例 php 代码:

    interface DbTable
    {
        public function doSomething(): void;
    }
    
    class MySqlTable implements DbTable
    {
        public function doSomething(): void
        { }
    }
    
    class OracleTable implements DbTable
    {
        public function doSomething(): void
        { }
    }
    
    class TableFactory
    {
        public static function createTable(string $type = null): DbTable
        {
            if ($type === 'oracle') {
                return new OracleTable();
            }
            return new MySqlTable(); // default is mysql
        }
    }
    
    // client
    $oracleTable = TableFactory::createTable('oracle');
    $oracleTable->doSomething();
    

    为了让它更动态(以后少修改):

    interface DbTable
    {
        public function doSomething(): void;
    }
    
    class MySqlTable implements DbTable
    {
        public function doSomething(): void
        { }
    }
    
    class OracleTable implements DbTable
    {
        public function doSomething(): void
        { }
    }
    
    class TableFactory
    {
        public static function createTable(string $tableName = null): DbTable
        {
            $className = __NAMESPACE__ . $tableName . 'Table';
            if (class_exists($className)) {
                $table = new $className();
                if ($table instanceof DbTable) {
                   return $table;
                }
            }
            throw new \Exception("Class $className doesn't exists or it's not implementing DbTable interface");
        }
    }
    
    $tbl = TableFactory::createTable('Oracle');
    $tbl->doSomething();
    

    【讨论】:

    • 这看起来更像是简单工厂而不是工厂方法模式。据我了解,工厂方法模式提供了多个具体工厂,这些工厂创建了继承自同一个抽象产品的具体产品实例。如果我觉得只有一个工厂就足以根据客户端传递的类型字符串(或枚举)来决定要实例化哪个具体产品,那么即使是简单工厂也足够了。为什么在这种情况下需要使用工厂方法模式?
    • @ndh 做了一些改变 :)
    【解决方案3】:

    来自我现在正在开发的 API:

    WebGalleryFactory factory = WebGalleryFactory.newInstance (WebGalleryType.PICASA);
    WebAlbum album = factory.createAlbum (title, description);
    

    在本例中,我使用工厂方法创建某种类型的抽象工厂(示例中为 PICASA)。

    这两种模式经常一起使用。

    【讨论】:

    • 为什么不显式实例化 PicasaWebGalleryFactory?
    • 为什么它是工厂?难道不能有一个 WebGallery 类和一个 PicasaWebGallery 子类吗?
    【解决方案4】:

    Zend_Db 在其Zend_Db_Adapter 类中使用它,以允许根据从配置对象传递的数据库设置创建不同类型的数据库对象。

    【讨论】:

    • 工厂方法的其他例子:Zend_Cache::factory(), Zend_Memory::factory()。 Zend_Log_Writer 也有工厂方法用于初始化 Zend_Log_Writer_Abstract 的具体适配器。但是必须注意一件事:当工厂方法直接注入产品时,这些实现通常是形式上的(即没有单独的 AbstractCreator/ConcreteCreator 类)。
    • 刚刚重新检查了代码:ZF 实际上使用了所谓的简单工厂,这是成语而不是模式(在 HF 设计模式中有描述)。我还看到了一堆静态工厂方法,至少实现与 Bloch 在 Effective Java 中讨论的非常相似。而且我找不到确切的 GoF 实现的工厂方法模式。
    【解决方案5】:

    .NET 基类库 (BCL) 中的一个示例是Control.CreateControlsInstance,它被(Windows 窗体)控件类的许多其他成员使用。

    您可以覆盖此受保护的方法以提供您自己的控件集合,例如实现自定义控件时。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-04
      • 2019-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多