这是工厂模式的工作原理吗?

时间:2010-01-26 09:17:41

标签: php design-patterns factory-pattern

单身人士和注册表模式非常简单,我很容易立即理解,但工厂模式一直是我无法让我的大脑100%解释的东西。我想我现在可能会理解它,我在下面写了一个示例代码,请查看并告诉我这是否正确使用了Factory模式。示例是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();

?>

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


更新#1

这是基于这里的一篇博客文章我在这里阅读http://www.potstuck.com/2009/01/08/php-dependency-injection/他们称之为“工厂”,我一直在使用注册表,很多人一直告诉我要看一下“工厂”我读到的所有内容都没有点击我的脑袋,直到我读到这个艺术品,但看起来它不是“工厂”?


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

所以这可能是一个“工厂对象”,毕竟......

5 个答案:

答案 0 :(得分:6)

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

像其他人说的那样,它不是 Factory ,只是因为不存在具有此名称的模式。它既可以是 AbstractFactory ,也可以是 FactoryMethod ,但实际上人们经常会引用 Factory 或者只是说 Factory ,这对我没用。

会话,缓存和数据库通常是您将在应用程序流程中尽早初始化的内容,因此这基本上是自举工作。我得到的印象是,您所寻找的不是对象的创建,而是整个应用程序中的处理。这与 FactoryWhatever 的作用有些不同。

就像我在评论中所说的那样,仅仅因为它不是 FactoryWhatever ,并不代表你的代码是坏的。如果它解决了你的问题,那很酷。但我仍然认为,你要做的是,例如在运行时创建管理资源最好与DI Service Container一起使用。

如果你现在不想使用DI容器 ,你可以查看Zend_Application and how they bootstrap resources。它是另一种选择,可以add DI containers later.

事实上,您以前的问题中的很多主题已经在Zend Framework中得到了解决,例如配置类。我不是说使用ZF,但是你可以看看它们是如何做的。当然,您也可以查看other frameworks

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

答案 1 :(得分:5)

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

虽然从技术上讲你可以称它为工厂模式,但它可能不是模式的好用法。 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();
}

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

class UserFactory {
    public static User createUser(Integer reputation) {
        ...
    }
}

答案 2 :(得分: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();
        }
    }

答案 3 :(得分:2)

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

工厂方法的想法与框架有关:你想在一些框架代码中创建一个用法,但实际的用户实现是在派生类中,即你的框架的用户编写自己的应用程序 - 就在你需要的时候告诉用户你的框架“现在创建一个用户对象”,这是对工厂方法的调用。用户必须实现此目的。根据GoF,它也被称为Virtual Contstructor。

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

答案 4 :(得分:1)

对我来说,看起来更像是Builder模式。您实际意味着哪种工厂模式,AbtractFactory或FactoryMethod?但是,它们都处理继承,而代码只是组装一个“复杂”的对象。