8

单例模式和注册表模式对我来说非常简单易懂,但工厂模式一直是我无法让我的大脑 100% 解释的东西。我想我现在可能明白了,我在下面写了一个示例代码,请检查并告诉我这是否是工厂模式的正确使用。示例在 PHP...

<?php
 /**
 *   Factory.class.php
 */
class Factory {
    public static $_database;
    public static $_cache;
    public static $_session;

    // Build our User object with all it's dependencies  
    public static function makeUserObject()
    {
        $user = new User();
        $user->setDatabaseObject(self::$_database);
        $user->setCacheObject(self::$_cache);
        $user->setSessionObject(self::$_session);
        return $user;
    }

    // other objects will be here someday......
}

/**
 *  User.class.php
 */
class User
{
    public function __construct() { }

    // inject Database Object
    public function setDatabaseObject($databaseConnectionObject)
    {
        $this->_databaseObject = $databaseConnectionObject;
    }

    // inject Cache Object
    public function setCacheObject($cacheObject)
    {
        $this->_cacheObject = $cacheObject;
    }

    // inject Session Object
    public function setSessionObject($sessionObject)
    {
        $this->_sessionObject = $sessionObject;
    }

    // other methods here for User object...........
}

/**
 *  index.php  Main page that puts it all together
 *  assume that classes are autoloaded into this page already
 */
// Set our Database + Cache + Session objects into the Factory Object
Factory::$_database = new Databse();
Factory::$_cache = new Cache();
Factory::$_session = new Session();

// Create our User object
// The factory class will build the User object and inject all
// it's dependencies for us =)
$user = Factory::makeUserObject();

?>

所以基本上创建了数据库、缓存和会话对象(此处未显示),然后将它们添加到工厂对象中,我可以在工厂类中为每个需要这 3 个依赖项中的任何一个的对象构建一个方法,我可以设置他们也得到哪些。这也使得单个类仍然可以在某种程度上具有可移植性,因为如果我想在没有工厂对象的情况下直接注入依赖项的话。这听起来对吗?如果这是正确的,这听起来真的很有用


更新#1

这是基于我在此处阅读的博客文章http://www.potstuck.com/2009/01/08/php-dependency-injection/他们将其称为“工厂”,我一直在使用注册表和很多人一直告诉我要研究一个“工厂”,而我读到的所有关于它的内容都没有在我的脑海中点击,直到我读到这篇文章但看起来它不是一个“工厂”?


更新 #2
来自维基百科 http://en.wikipedia.org/wiki/Factory_object 在面向对象的计算机编程中,工厂对象是用于创建其他对象的对象。它是构造函数的抽象,可用于实现各种分配方案,例如单例模式。工厂对象通常为它能够创建的每一种对象都有一个方法。这些方法可选地接受定义如何创建对象的参数,然后返回创建的对象。工厂对象用于获取特定类型的对象是一个比简单地创建新对象更复杂的过程的情况。工厂对象可能决定动态地创建对象的类(如果适用)、从对象池中返回它、对对象进行复杂的配置或其他事情。

所以也许这毕竟是一个“工厂对象”......

4

5 回答 5

6

从这里的问题下方总结并扩展了我的评论

就像其他人说的那样,它不是Factory,只是因为不存在具有此名称的模式。它要么是AbstractFactory要么是FactoryMethod,尽管实际上人们经常指代这两者或只是说Factory,这对我来说很好。

会话、缓存和数据库通常是您在应用程序流程的早期初始化的东西,所以这基本上是引导工作。我得到的印象是您正在寻找的不是对象的创建,而是它们在整个应用程序中的处理。这与FactoryWhatever所做的事情有些不同。

就像我在评论中所说的那样,仅仅因为它不完全是FactoryWhatever,并不意味着您的代码不好。如果它解决了你的问题,那就太好了。但我仍然认为,您正在尝试做的事情,例如在运行时创建管理资源最好与DI Service Container一起使用。

如果您现在不想为此使用 DI 容器,您可以查看Zend_Application 以及它们如何引导资源。这是一种替代方法,可以在以后添加 DI 容器。

事实上,您之前的问题中的很多主题已经在 Zend Framework 中得到解决,例如 Config 类。我不是说使用 ZF,但你可以检查一下,看看他们是如何做事的。当然,您也可以查看其他 框架

一些带有 PHP 示例的模式站点:

于 2010-01-26T10:15:31.603 回答
5

那是工厂模式好吧,但您可能需要一个比仅调用它更好的命名约定Factory。它还包含依赖注入的痕迹。

尽管从技术上讲,您可以将其称为工厂模式,但它可能不是该模式的良好用法。工厂是一种创建模式,它将您的代码从直接引用类名和对象创建中封装为精确的构造函数参数等。为了获得最佳结果,请在设计类和工厂时牢记这一点。

例如,StackOverflow会根据用户的声誉得分赋予用户不同的权限。假设地说,它可能有以下类型的用户:

NewbieUser      [1-100]
BeginnerUser    [101-1000]
AverageJoeUser  [1001-5000]
VeteranUser     [5001-20000]
PowerUser       [20001-50000]
GodModeUser     [50001-100000]

并且可以通过查找他们的代表来创建用户。并通过直接引用该类来实例化相应的用户对象。如果您想知道,Jon Skeet 不会出现在任何类别中。这是一个直接实例化的糟糕实现:

if(reputation >= 1001 and reputation <= 5000) {
    AverageJoeUser user = new AverageJoeUser();
}

如果以后我们要更改类名或实例化用户的方式,则必须找到并更改创建对象的每个此类实例。如果你问我,工作量很大。相反,如果我们在这里使用了工厂模式,则更改将在工厂类中的单个方法中进行。

class UserFactory {
    public static User createUser(Integer reputation) {
        ...
    }
}
于 2010-01-26T09:51:03.227 回答
3

对我来说看起来不像工厂——可能是一个由内而外的建造者?;0)

工厂是一种隐藏实现和实例化的方式。通常会进行一些组装,但简而言之....

  public interface IUser
    {
        void DoSomething();
    }

    public class DumbUser : IUser
    {

        public void DoSomething()
        {
            // duh... what should i do?
        }

    }

    public class SmartUser : IUser
    {

        public void DoSomething()
        {
            // calclulating prime numbers while baking bread
        }

    }


    public class UserFactory
    {
        public static IUser CreateUser()
        {
            Random r = new Random(Environment.TickCount);

            return r.Next(10) > 5 ? (IUser) new SmartUser() : new DumbUser();
        }
    }

    public class YourProgram
    {
        public void Run()
        {
            IUser user = UserFactory.CreateUser();
            user.DoSomething();
        }
    }
于 2010-01-26T09:31:12.430 回答
2

由于您似乎只是想创建一个用户,因此我认为不需要抽象因素,此后简称为工厂。工厂的想法是创建实现特定接口的对象。您希望能够实例化同一接口的两个不同实现。关键是您可能必须一遍又一遍地创建这些对象,并且在整个代码中将其从 ObjectA 更改为 ObjectB 很麻烦。更换工厂很容易,因为它通常是单例的。

工厂方法的思想与框架有关:你想在一些框架代码中创建一个使用,但实际的用户实现是在派生类中,即你的框架的用户正在编写他们自己的应用程序——也就是当你需要告诉你框架的用户“现在创建一个用户对象”,这是对工厂方法的调用。用户必须实现这一点。根据 GoF,它也被称为虚拟构造器。

当对象有不同的表示形式时,通常会使用构建器,但此处并非如此。在我看来,缓存、数据库和会话可以实现为单例,从而简化了所涉及的复杂性。否则,我建议使用 ServiceLocator ,它允许您GetDatabase,GetSession等。然后,您必须在创建时将定位器传递给用户对象(和许多其他对象)。好处是这个定位器可以在不同的类中重用。

于 2010-01-26T09:49:17.370 回答
1

在我看来更像是建造者模式。您实际上是指哪种工厂模式,AbtractFactory 或 FactoryMethod?但是,它们都处理继承,您的代码只是组装一个“复杂”对象。

于 2010-01-26T09:23:33.220 回答