当建模类时,首选的初始化方式是什么:
构造函数,或者
工厂方法
使用它们的考虑是什么?
在某些情况下,我更喜欢有一个工厂方法,如果对象不能被构造,它就返回null。这使得代码整洁。在采取替代操作之前,我可以简单地检查返回值是否不为空,而不是从构造函数抛出异常。(我个人不喜欢例外)
比如说,我在一个类上有一个构造函数,它需要一个id值。构造函数使用这个值从数据库填充类。如果指定id的记录不存在,构造函数抛出RecordNotFoundException异常。在这种情况下,我将不得不在一个try. catch块中包含所有此类类的构造。
与此相反,我可以在那些类上有一个静态工厂方法,如果没有找到记录将返回null。
在这种情况下,哪种方法更好,构造函数方法还是工厂方法?
问问你自己它们是什么,为什么我们会有它们。它们都用于创建对象的实例。
ElementarySchool school = new ElementarySchool();
ElementarySchool school = SchoolFactory.Construct(); // new ElementarySchool() inside
到目前为止没有区别。现在想象一下,我们有各种各样的学校类型,我们想从使用ElementarySchool切换到HighSchool(它是从ElementarySchool派生出来的,或者实现了与ElementarySchool相同的isschool接口)。代码更改如下:
HighSchool school = new HighSchool();
HighSchool school = SchoolFactory.Construct(); // new HighSchool() inside
在接口的情况下,我们将有:
ISchool school = new HighSchool();
ISchool school = SchoolFactory.Construct(); // new HighSchool() inside
现在,如果你在多个地方都有这段代码,你可以看到使用工厂方法可能非常便宜,因为一旦你改变了工厂方法,你就完成了(如果我们使用接口的第二个例子)。
这是主要的区别和优势。当您开始处理复杂的类层次结构并希望从这样的层次结构中动态创建类的实例时,您会得到以下代码。然后,工厂方法可以接受一个参数,该参数告诉方法要实例化哪个具体实例。假设您有一个MyStudent类,您需要实例化相应的ISchool对象,以便您的学生是该学校的成员。
ISchool school = SchoolFactory.ConstructForStudent(myStudent);
现在,您在应用程序中有了一个包含业务逻辑的地方,该业务逻辑决定为不同的IStudent对象实例化哪个ISchool对象。
因此,对于简单的类(值对象等),构造函数是很好的(你不想过度设计你的应用程序),但对于复杂的类层次结构,工厂方法是首选的方法。
这样你就遵循了四人组书中的第一个设计原则“编程到接口,而不是实现”。
在创建对象时,有时必须检查/计算一些值/条件。如果它可以抛出一个异常-构造函数是非常糟糕的方式。所以你需要这样做:
var value = new Instance(1, 2).init()
public function init() {
try {
doSome()
}
catch (e) {
soAnotherSome()
}
}
所有额外的计算都在init()中。但是只有作为开发人员的您才真正了解这个init()。当然,几个月后你就会忘记它。
但是如果你有一个工厂——你只需要在一个方法中隐藏init()以避免直接调用——所以没有问题。使用这种方法不存在创建失败和内存泄漏的问题。
有人告诉过你缓存。很好。但你也必须记住Flyweight模式,它很适合与Factory方式一起使用。
除了“有效的java”(在另一个答案中提到),另一本经典书也建议:
首选静态工厂方法(具有描述参数的名称)而不是重载构造函数。
如。不要写
Complex complex = new Complex(23.0);
而是写
Complex complex = Complex.fromRealNumber(23.0);
这本书甚至建议将Complex(float)构造函数设为私有,以强制用户调用静态工厂方法。