与同事讨论过这是不好的做法。现在我在网上找不到这个例子。
我们有很多数据库对象映射器并且像它这样调用它的函数
(示例) - 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
}
答案 0 :(得分:14)
这不是可怕的 persay。它是Factory Method设计模式的实现。原则上它一点也不差。
但是,在你的具体例子中,它并没有真正做任何重要的事情,所以我不确定是否有必要。您可以通过将(可能是可选的)参数添加到id的构造函数来消除这种需要。然后任何人都可以调用$foo = new Person($id);
而不是需要一个明确的工厂。
但是如果实例化很复杂,或者您希望能够构建几个只能由逻辑确定的不同人员类型,那么工厂方法可能会更好。例如,假设您需要确定某个参数实例化的人员类型。然后,Person
上的工厂方法是合适的。该方法将确定要加载的“类型”,然后实例化该类。
一般来说静态很难测试,并且不允许像实例那样进行多态变更。它们还在代码中的类之间创建硬依赖关系。它们不是可怕的,但如果你想使用它,你应该考虑它。一个选项是使用Builder或Abstract Factory。这样,您可以创建构建器/工厂的实例,然后让该实例确定如何实例化生成的类...
另一个注意事项。我会将该方法从Person::get()
重命名为更符合语义的方法。也许是Person::getInstance()
或其他合适的东西。
答案 1 :(得分:5)
这篇博文应该告诉你为什么人们不喜欢静态方法比我更好:
http://kore-nordmann.de/blog/0103_static_considered_harmful.html
关于您当前的代码段最让我印象深刻的问题:是否允许某人没有ID?
我觉得如果它代表一个真人,那应该是一个构造函数参数。如果您使用该类创建可能无效的新人。
两次通话之间的差异很小。两者都“创建”一个Person类并设置Id,这样当你遇到“硬连线依赖”时你就不会赢得/失去任何东西。
优势仅显示当您希望能够将Person传递到另一个对象并且该对象需要更改ID时(例如,博客文章应该比我在此更好地解释)。
答案 2 :(得分: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 :(得分:1)
长话短说,是的,他们是不好的做法:
除了一切之外,一个很好的理由是你应该'测试你的代码。静态方法会导致问题,所以你有充分的理由:
答案 4 :(得分:0)
时间随时间变化。
万一测试遇到问题,可以使用AspectMock库 https://github.com/Codeception/AspectMock
任何方式静态都没有那么糟糕。要使用静态,您应该只知道自己在做什么以及为什么。如果仅将静态作为快速解决方案放置,那么在99%的变化中这是个坏主意。在1%的时间内,它仍然是一个糟糕的解决方案,但是它可以在需要时为您提供时间。