构造函数与工厂方法
在build模时,什么是初始化的首选方法:
- 构造函数,或
- 工厂方法
而使用其中之一的考虑是什么?
在某些情况下,我更喜欢有一个工厂方法,如果无法构造对象,则返回null。 这使得代码整齐。 我可以简单地检查在采取替代动作之前返回的值是否为空,与从构造函数中抛出exception相反。 (我个人不喜欢例外)
说,我有一个类的构造函数,期望一个id值。 构造函数使用此值从数据库填充类。 在具有指定id的logging不存在的情况下,构造函数将引发RecordNotFoundException。 在这种情况下,我将不得不在try..catch块中包含所有这些类的构造。
相比之下,我可以有一个静态工厂方法的那些类将返回null,如果没有findlogging。
在这种情况下,构造函数还是工厂方法哪种方法更好?
从devise模式的第108页:Gamma,Helm,Johnson和Vlissides的可重用面向对象软件的元素。
使用工厂方法模式
- 一个类不能预测它必须创build的对象的类
- 一个类想让它的子类指定它创build的对象
- 类将责任委派给几个助手子类之一,并且你想本地化哪些助手子类是委托的知识
问问自己,他们是什么,为什么我们有他们。 他们都在那里创build一个对象的实例。
ElementarySchool school = new ElementarySchool(); ElementarySchool school = SchoolFactory.Construct(); // new ElementarySchool() inside
迄今为止没有什么不同 现在想象一下,我们有不同的学校types,我们希望从使用小学(ElementarySchool)转到高中(HighSchool)(这是从小学学校衍生出来的,或者实现与小学学校相同的接口)。 代码更改将是:
HighSchool school = new HighSchool(); HighSchool school = SchoolFactory.Construct(); // new HighSchool() inside
在接口的情况下,我们将有:
ISchool school = new HighSchool(); ISchool school = SchoolFactory.Construct(); // new HighSchool() inside
现在,如果你在多个地方有这个代码,你可以看到使用工厂方法可能是相当便宜的,因为一旦你改变了工厂方法,你完成了(如果我们使用第二个例子的接口)。
这是主要的区别和优势。 当你开始处理一个复杂的类层次结构,并且你想从这样的层次结构中dynamic地创build一个类的实例时,你会得到下面的代码。 然后,工厂方法可能需要一个参数来告诉方法实例化的具体实例。 比方说,你有一个MyStudent类,你需要实例化相应的ISchool对象,以便你的学生是该学校的成员。
ISchool school = SchoolFactory.ConstructForStudent(myStudent);
现在,您的应用程序中有一个地方包含业务逻辑,该业务逻辑确定为不同IStudent对象实例化的ISchool对象。
所以 – 对于简单的类(值对象等)构造函数就好(你不想过度工程你的应用程序),但对于复杂的类层次结构工厂方法是一个首选的方法。
这样你就可以遵循四本书 “程序到界面,而不是实现”的帮派的第一个devise原则。
您需要阅读(如果您有权访问) Effective Java 2 项目1:考虑静态工厂方法而不是构造函数 。
静态工厂方法的优点:
- 他们有名字。
- 每次调用它们时都不需要创build一个新的对象。
- 他们可以返回任何他们的返回types的子types的对象。
- 它们减less了创build参数化types实例的冗长度。
静态工厂方法的缺点:
- 当仅提供静态工厂方法时,不具有公共或受保护的构造函数的类不能被分类。
- 他们不容易区别于其他静态方法
默认情况下,构造函数应该是首选的,因为它们更易于理解和编写。 但是,如果您特别需要将对象的构造细节与客户代码所理解的语义相分离,则最好使用工厂。
构造函数和工厂之间的区别就像是一个variables和一个指向variables的指针。 还有另一个层次的间接,这是一个劣势。 但还有另一个灵活性,这是一个优势。 所以在做出select的时候,你最好做这个成本与收益的分析。
从“Effective Java”第二版中引用,第1项:考虑静态工厂方法,而不是构造函数,p。 5:
“请注意, 静态工厂方法与devise模式中的工厂方法模式不同 [Gamma95,p.107]。此项中描述的静态工厂方法在devise模式中没有直接的等价物。
仅在需要使用对象创build进行额外控制时才使用工厂,而这种方式无法通过构造函数完成。
例如,工厂有可能进行caching。
另一种使用工厂的方法是在您不知道要构build的types的情况下。 通常你会在插件工厂场景中看到这种types的用法,其中每个插件必须从基类派生或实现某种types的接口。 工厂创build从基类派生或实现接口的类的实例。
一个CAD / CAM应用程序的具体例子。
切割path将通过使用构造函数来完成。 这是一系列定义切割path的线条和弧线。 虽然一系列的线条和弧线可以是不同的,并且有不同的坐标,但是通过将列表传递给构造函数可以很容易地进行处理。
一个形状将会通过使用一个工厂。 因为虽然有一个形状类,每个形状将根据它是什么types的形状设置不同。 我们不知道我们将要初始化的形状,直到用户做出select。
说,我有一个类的构造函数,期望一个id值。 构造函数使用此值从数据库填充类。
这个过程肯定在构造函数之外。
-
构造函数不应该访问数据库。
-
构造函数的任务和原因是初始化数据成员,并使用传递给构造函数的值build立类不variables 。
-
对于其他方面来说,更好的方法是使用静态工厂方法,或者在更复杂的情况下使用单独的工厂或构build器类。
Microsoft的一些构造函数指南 :
在构造函数中做最小的工作。 除了捕获构造函数参数外,构造函数不应该做很多工作。 任何其他处理的成本应该推迟到需要的时候。
和
如果所需操作的语义不直接映射到新实例的构造,请考虑使用静态工厂方法而不是构造函数。