我知道有一些模式,如注册表,单身等等。
是否存在用于处理对象的设计模式,这些模式不应该全局可用,而只能在局部区域中使用,以便我可以为同一个角色设置不同的对象?例如,如果我使用单例,我在整个程序中有相同的对象,这不是我想要的。
答案 0 :(得分:1)
处理对象创建的常见模式是Gang of Four Creational Patterns。
引用维基百科:
创建模式是为您创建对象的模式,而不是直接实例化对象。这为您的程序提供了更大的灵活性,可以决定需要为给定的案例创建哪些对象。
- Abstract Factory对具有共同主题的对象工厂进行分组。
- Builder通过分离构造和表示来构造复杂对象。
- Factory Method创建对象而不指定要创建的确切类。
- Prototype通过克隆现有对象来创建对象。
- Singleton将对象的对象限制为仅限一个实例。
有关创建实例职责的一般经验法则,请查看Wikipedia's article about GRASP:
中的创建者模式一般来说,如果下列一个或更好的更多,B类应负责创建A类实例:
- B的实例包含或复合地聚合A
的实例- A
的B记录实例的实例- B的实例密切使用A
的实例- B的实例具有A实例的初始化信息,并在创建时传递。
GoF Creational Patterns是对此的补充。例如,如果您使用Factory模式,Factory可能会保存A实例的初始化信息,并在创建时传递它:
class BMWFactory implements CarFactory
{
// properties, ctors and stuff …
public function createCar($color)
{
return new Bmw(
$color,
// … more arguments
);
}
}
另一方面,它也意味着可以允许Collection创建新实例,因为B然后“包含或复合地聚合A的实例”,这将导致类似
的内容class Cars
{
// properties, ctors and stuff …
public function createCar($color)
{
return new Car(/* … */);
}
}
$bmws = new Cars($config['bmw']);
$bmws[] = $bmws->createCar('alpine white');
我们可以争论,当创建的对象具有独立的生命周期时,让集合创建对象而不是仅存储它们是否是个好主意。如果由B创建的As具有相同的生命周期,则它是另一回事。
除了让B创建为As,您还可以delegate创建工厂:
class Cars
{
// properties, ctors and stuff …
public function createCar($color)
{
return $this->carFactory->createNewCar(/* … */);
}
}
$bmws = new Cars(new BmwFactory);
$bmws[] = $bmws->createCar('alpine white');
您应该始终仔细考虑在代码中使用new
的原因是因为它引入了从B到A的强耦合。注入工厂会松开耦合,尤其是因为我们programmed to an interface代替了混凝土类。
强耦合使得在单元测试中模拟协作者变得困难。 Quoting Miško Hevery's How to Think About the “new” Operator with Respect to Unit Testing
但是依赖注入如此重要的原因是,在单元测试中,您希望测试应用程序的一小部分。要求是您可以独立于整个系统构建应用程序的这个小子集。如果将应用程序逻辑与图形构造混合(新运算符),除了应用程序中的叶节点之外,任何其他内容都不可能进行单元测试。
在他的Google Talk中进一步解释了将创建与应用程序逻辑分离的想法,该对话在我的相关答案Dependency Hell — how does one pass dependencies to deeply nested objects?中进行了链接。基本思想是组装您可以在工厂或构建器中或通过依赖注入容器预先合理组装的所有内容。
如果要在本地范围内创建对象(因为它取决于运行时信息),请将Creation逻辑封装到Factories或Builders中,并将这些逻辑注入到包含运行时信息的对象中,并将信息委托给工厂和构建器。从那里需要的时候。