Ask yourself what they are and why do we have them. They both are there to create instance of an object.
ElementarySchool school = new ElementarySchool();
ElementarySchool school = SchoolFactory.Construct(); // new ElementarySchool() inside
No difference so far. Now imagine that we have various school types and we want to switch from using ElementarySchool to HighSchool (which is derived from an ElementarySchool or implements the same interface ISchool as the ElementarySchool). The code change would be:
HighSchool school = new HighSchool();
HighSchool school = SchoolFactory.Construct(); // new HighSchool() inside
In case of an interface we would have:
ISchool school = new HighSchool();
ISchool school = SchoolFactory.Construct(); // new HighSchool() inside
Now if you have this code in multiple places you can see that using factory method might be pretty cheap because once you change the factory method you are done (if we use the second example with interfaces).
And this is the main difference and advantage. When you start dealing with a complex class hierarchies and you want to dynamically create an instance of a class from such a hierarchy you get the following code. Factory methods might then take a parameter that tells the method what concrete instance to instantiate. Let's say you have a MyStudent class and you need to instantiate corresponding ISchool object so that your student is a member of that school.
ISchool school = SchoolFactory.ConstructForStudent(myStudent);
Now you have one place in your app that contains business logic that determines what ISchool object to instantiate for different IStudent objects.
So - for simple classes (value objects, etc.) constructor is just fine (you don't want to overengineer your application) but for complex class hierarchies factory method is a preferred way.
This way you follow the first design principle from the gang of four book "Program to an interface, not an implementation".
By default, constructors should be preferred, because they are simpler to understand and write. However, if you specifically need to decouple the construction niceties of an object from its semantic meaning as understood by the client code, you'd be better off using factories.
The difference between constructors and factories is analogous to, say, a variable and a pointer to a variable. There's another level of indirection, which is a disadvantage; but there's another level of flexibility too, which is an advantage. So while making a choice, you'd be well advised to do this cost versus benefit analysis.
Use a factory only when you need extra control with object creation, in a way that couldn't be done with constructors.
Factories have the possibility of caching for example.
Another way to use factories is in a scenario where you do not know the type you want to construct. Often you see this type of usage in plugin factory scenarios, where each plugin must derive from a baseclass or implement some kind of interface. The factory creates instances of classes that derive from the baseclass or that implement the interface.
A cite from "Effective Java", 2nd ed., Item 1: Consider static factory methods instead of constructors, p. 5:
"Note that a static factory method is not the same as the Factory Method pattern from Design Patterns [Gamma95, p. 107]. The static factory method described in this item has no direct equivalent in Design Patterns."
A cutting path would be made by using a constructor. It is a series of lines and arcs defining a path to cut. While the series of lines and arcs can be different and have different coordinates it easily handled by passing a list into a constructor.
A shape would be would be made by using a factory. Because while there is a shape class each shape would be setup differently depending on what type of shape it is. We don't know what shape we are going to be initializing until the user makes a selection.
Do minimal work in the constructor. Constructors should not do much work other than to capture the constructor parameters. The cost of any other processing should be delayed until required.
And
Consider using a static factory method instead of a constructor if the semantics of the desired operation do not map directly to the construction of a new instance.
Sometimes you have to check/calculate some values/conditions while creating an object. And if it can throw an Exception - constructro is very bad way. So you need to do something like this:
var value = new Instance(1, 2).init()
public function init() {
try {
doSome()
}
catch (e) {
soAnotherSome()
}
}
Where all additional calculations are in init(). But only you as developer realy know about this init(). And of course, after months you just forget about it. But if you have a factory - just do all you need in one method with hiding this init() from direct call - so no problems. With this approach is no problems with falling on creation and memory leaking.
Someone told you about caching. It's good. But you also have to remember about Flyweight pattern which is nice to use with Factory way.
发布评论
评论(10)
问问自己它们是什么以及为什么我们有它们。 它们都是为了创建对象的实例。
到目前为止没有区别。 现在假设我们有各种学校类型,并且希望从使用 ElementarySchool 切换到 HighSchool(它派生自 ElementarySchool 或实现与 ElementarySchool 相同的接口 ISchool)。 代码更改将是:
如果是接口,我们将拥有:
现在,如果您在多个地方都有此代码,您可以看到使用工厂方法可能非常便宜,因为一旦您更改工厂方法,您就完成了(如果我们使用第二个带有接口的示例)。
这是主要的区别和优势。 当您开始处理复杂的类层次结构并且想要从此类层次结构动态创建类的实例时,您将获得以下代码。 然后,工厂方法可能会采用一个参数来告诉该方法要实例化哪个具体实例。 假设您有一个 MyStudent 类,并且您需要实例化相应的 ISchool 对象,以便您的学生成为该学校的成员。
现在,您的应用程序中有一处包含业务逻辑,用于确定为不同的 IStudent 对象实例化哪个 ISchool 对象。
因此,对于简单的类(值对象等),构造函数就可以了(您不想过度设计您的应用程序),但对于复杂的类层次结构,工厂方法是首选方式。
这样,您就可以遵循四本书中的第一个设计原则“编程一个接口,而不是一个实现”。
Ask yourself what they are and why do we have them. They both are there to create instance of an object.
No difference so far. Now imagine that we have various school types and we want to switch from using ElementarySchool to HighSchool (which is derived from an ElementarySchool or implements the same interface ISchool as the ElementarySchool). The code change would be:
In case of an interface we would have:
Now if you have this code in multiple places you can see that using factory method might be pretty cheap because once you change the factory method you are done (if we use the second example with interfaces).
And this is the main difference and advantage. When you start dealing with a complex class hierarchies and you want to dynamically create an instance of a class from such a hierarchy you get the following code. Factory methods might then take a parameter that tells the method what concrete instance to instantiate. Let's say you have a MyStudent class and you need to instantiate corresponding ISchool object so that your student is a member of that school.
Now you have one place in your app that contains business logic that determines what ISchool object to instantiate for different IStudent objects.
So - for simple classes (value objects, etc.) constructor is just fine (you don't want to overengineer your application) but for complex class hierarchies factory method is a preferred way.
This way you follow the first design principle from the gang of four book "Program to an interface, not an implementation".
您需要阅读(如果您有权访问)Effective Java 2 第 1 项:考虑静态工厂方法而不是构造函数。
静态工厂方法的优点:
静态工厂方法的缺点:
You need to read (if you have access to) Effective Java 2 Item 1: Consider static factory methods instead of constructors.
Static factory methods advantages:
Static factory methods disadvantages:
来自 Gamma、Helm、Johnson 的 设计模式:可重用面向对象软件的元素的第 108 页, 时,请
使用工厂方法模式;
From page 108 of Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson, and Vlissides.
Use the Factory Method pattern when
默认情况下,应该首选构造函数,因为它们更易于理解和编写。 但是,如果您特别需要将对象的构造细节与其客户端代码所理解的语义含义解耦,那么最好使用工厂。
构造函数和工厂之间的区别类似于变量和指向变量的指针。 还有另一层间接性,这是一个缺点。 但还有另一个层面的灵活性,这是一个优势。 因此,在做出选择时,建议您进行成本与收益分析。
By default, constructors should be preferred, because they are simpler to understand and write. However, if you specifically need to decouple the construction niceties of an object from its semantic meaning as understood by the client code, you'd be better off using factories.
The difference between constructors and factories is analogous to, say, a variable and a pointer to a variable. There's another level of indirection, which is a disadvantage; but there's another level of flexibility too, which is an advantage. So while making a choice, you'd be well advised to do this cost versus benefit analysis.
仅当您需要对对象创建进行额外控制时才使用工厂,而使用构造函数无法做到这一点。
例如,工厂可以进行缓存。
使用工厂的另一种方法是在您不知道要构造的类型的情况下。 通常,您会在插件工厂场景中看到这种类型的用法,其中每个插件必须从基类派生或实现某种接口。 工厂创建派生自基类或实现接口的类的实例。
Use a factory only when you need extra control with object creation, in a way that couldn't be done with constructors.
Factories have the possibility of caching for example.
Another way to use factories is in a scenario where you do not know the type you want to construct. Often you see this type of usage in plugin factory scenarios, where each plugin must derive from a baseclass or implement some kind of interface. The factory creates instances of classes that derive from the baseclass or that implement the interface.
除了另一个答案中提到的“efficient java”之外,另一本经典书籍(《干净的代码:敏捷软件工艺手册》)还建议:
当构造函数重载时,请使用名称描述参数的静态工厂方法。 不要写
,而是写。
本书甚至建议将
Complex(float)
构造函数设为私有,以强制用户调用静态工厂方法。In addition to "effective java" mentioned in another answer, another classic book (Clean Code: A Handbook of Agile Software Craftsmanship) also suggests:
When constructors are overloaded, use static factory methods with names that describe the arguments. Don't write
but instead write
The book goes as far as to suggest making the
Complex(float)
constructor private, to force the user to call the static factory method.引用自“Effective Java”,第二版,第 1 项:考虑静态工厂方法而不是构造函数,第 14 页。 5:
“请注意,静态工厂方法与工厂方法模式不同
摘自《设计模式》 [Gamma95,第 14 页] 107]。 静态工厂方法描述于
该项目在设计模式中没有直接等效项。”
A cite from "Effective Java", 2nd ed., Item 1: Consider static factory methods instead of constructors, p. 5:
"Note that a static factory method is not the same as the Factory Method pattern
from Design Patterns [Gamma95, p. 107]. The static factory method described in
this item has no direct equivalent in Design Patterns."
CAD/CAM 应用程序的具体示例。
将使用构造函数来创建切割路径。 它是一系列定义切割路径的直线和弧线。 虽然一系列直线和弧可以不同并且具有不同的坐标,但通过将列表传递到构造函数可以轻松处理。
形状将通过工厂来制作。 因为虽然存在形状类,但每个形状都会根据形状的类型进行不同的设置。 在用户做出选择之前,我们不知道要初始化什么形状。
A concrete example from a CAD/CAM application.
A cutting path would be made by using a constructor. It is a series of lines and arcs defining a path to cut. While the series of lines and arcs can be different and have different coordinates it easily handled by passing a list into a constructor.
A shape would be would be made by using a factory. Because while there is a shape class each shape would be setup differently depending on what type of shape it is. We don't know what shape we are going to be initializing until the user makes a selection.
这个过程绝对应该在构造函数之外。
构造函数不应访问数据库。
构造函数的任务和原因是初始化数据成员并使用传递到构造函数的值建立类不变性。
对于其他一切,更好的方法是使用静态工厂方法,或者在更复杂的情况下使用单独的工厂或构建器类。
来自 Microsoft 的一些构造函数指南:
和
This process should definitely be outside a constructor.
Constructor should not access database.
The task and the reason for a constructor is to initialize data members and to establish class invariant using values passed into constructor.
For everything else a better approach is to use static factory method or in more complex cases a separate factory or builder class.
Some constructor guide lines from Microsoft:
And
有时,您在创建对象时必须检查/计算一些值/条件。 如果它可以抛出异常 - 构造函数是非常糟糕的方式。 所以你需要做这样的事情:
所有额外的计算都在 init() 中。 但只有作为开发人员的您才真正了解这个 init()。 当然,几个月后你就会忘记它。
但是,如果您有一个工厂 - 只需在一种方法中完成您需要的所有操作,并隐藏此 init() 以防止直接调用 - 所以没有问题。 使用这种方法不存在创建失败和内存泄漏的问题。
有人告诉过你关于缓存的事情。 很好。 但您还必须记住 Flyweight 模式,它与 Factory 方式一起使用非常好。
Sometimes you have to check/calculate some values/conditions while creating an object. And if it can throw an Exception - constructro is very bad way. So you need to do something like this:
Where all additional calculations are in init(). But only you as developer realy know about this init(). And of course, after months you just forget about it.
But if you have a factory - just do all you need in one method with hiding this init() from direct call - so no problems. With this approach is no problems with falling on creation and memory leaking.
Someone told you about caching. It's good. But you also have to remember about Flyweight pattern which is nice to use with Factory way.