【问题标题】:Static method get - is this bad practice?静态方法 get - 这是不好的做法吗?
【发布时间】:2011-07-07 06:17:54
【问题描述】:

与一位同事讨论了这是否是不好的做法。现在我在网上找不到直接的例子。

我们有很多数据库对象映射器,并像这样调用它的函数

(示例)- setId 方法从数据库中获取行并将其设置为预定义的属性

class Person {

    public static function get($id) {
        $object = new Person;
        $object->setId($id);
        return $object;
    }
}

像这样使用它,我们可以使用这样的简单结构:(我们从例如帖子中获取 id)

$person = Person::get($id);

而不是

$person = new Person;
$person->setId($id);

现在,我的直觉告诉我这是不好的做法。但我无法解释。也许这里有人可以解释为什么这是,或者不是不好的做法

以下是我们如何使用它的一些其他示例。我们主要将它用于吸气剂。 (只是名字,不是代码。几乎所有的都只是运行一个查询,可以返回1个对象,然后使用结果的id来使用setId方法)

class CatalogArticle {
   public static function get($id) { }
   public static function getByArticlenumber($articlenumber) {} //$articlenumber is unique in the database
   public static function getRandom() {} //Runs a query returning a random row
}

【问题讨论】:

标签: php oop static-methods


【解决方案1】:

这篇博文应该告诉你为什么人们比我更不喜欢静态方法:

http://kore-nordmann.de/blog/0103_static_considered_harmful.html

关于您当前的代码 sn-p 最让我印象深刻的问题:是否允许 Person 没有 Id ?

如果它代表一个真实的人,我觉得它应该是一个构造函数参数。如果您使用该类来创建新的人员,则 ofc 可能无法正常工作。


两次调用之间的差异很小。两者都“创建”了一个 Person 类并设置了 Id,因此当涉及到“硬连线依赖”时,您不会在那里赢得/失去任何东西。

仅当您希望能够将 Person 传递给另一个对象并且对象需要更改 ID 时才会显示出优势(例如,博客文章应该比我在这里更好地解释这一点)。

【讨论】:

    【解决方案2】:

    我只是添加到 edorian 的帖子中,但我过去使用过静态 get 方法,其中有一个缓存引擎,并且(例如)我可能在 memcache 中有一个给定的 Person 对象,并且会而不是从缓存中检索它而不是进入数据库。

    例如:

    class Person {
    
        public static function get($id) {
    
            if(Cache::contains("Person", $id))
            {
               return Cache::get("Person", $id);
            }
            else
            {           
                //fictional get_person_from_database, basically
                //getting an instance of Person from a database
                $object = get_person_from_database($id);
            }
            return $object;
        }
    
    }
    

    通过这种方式,所有的缓存处理都由相关类完成,而不是调用者接人电话时不必担心缓存。

    【讨论】:

      【解决方案3】:

      这不是可怕的说法。它是Factory Method 设计模式的实现。原则上还不错。

      但是,在您的具体示例中,它并没有真正做任何重要的事情,所以我不太确定是否有必要。您可以通过将(可能是可选的)参数传递给 id 的构造函数来消除这种需要。然后任何人都可以打电话给$foo = new Person($id);,而不需要一个明确的工厂。

      但是如果实例化很复杂,或者您希望能够构建几种只能由逻辑确定的不同人员类型,那么工厂方法可能会更好。例如,假设您需要通过某个参数来确定要实例化的人的类型。然后,Person 上的工厂方法将是合适的。该方法将确定要加载的“类型”,然后实例化该类。

      一般来说,静态数据很难测试,并且不允许像实例那样进行多态更改。它们还在代码中的类之间创建硬依赖关系。它们并不可怕,但如果你想使用它们,你应该认真考虑一下。一个选项是使用BuilderAbstract Factory。这样,您创建了构建器/工厂的实例,然后让该实例确定如何实例化生成的类...

      另一个注释。我会将该方法从 Person::get() 重命名为更符合语义的名称。也许Person::getInstance() 或其他合适的东西。

      【讨论】:

        【解决方案4】:

        长话短说,是的,它们是不好的做法:

        除此之外,一个很好的理由是您“应该”测试您的代码。静态方法会导致问题,所以你有充分的理由:

        • 如果您想遵循良好做法,请测试您的代码
        • 因此,如果静态导致测试问题,静态会阻止编写测试,因此它会阻止遵循良好实践:-)

        【讨论】:

          【解决方案5】:

          时光荏苒,世事无常。

          万一您在测试时遇到问题,您可以使用 AspectMock 库 https://github.com/Codeception/AspectMock

          任何方式静态都不是那么糟糕。使用静态你应该知道你在做什么以及为什么。如果您将静态仅作为快速解决方案放置,那么在 99% 的变化中是个坏主意。在 1% 的时间内,它仍然是不好的解决方案,但它可以在您需要时给您时间。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-09-22
            • 2011-08-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多