考虑使用静态工厂方法代替构造器 -----《Effective Java》
静态工厂通常更加合适。因此切忌第一反应就是提供公有地构造器,而不先考虑静态工厂。
问题: 我们遇到需要对象地地方就使用new 关键字。当然 new 本身没有任何错,但是在修改了一些业务逻辑后,往往我们需要改变很多new 出来地对象地相关代码。业务代码地修改部分竟如此疯狂.
如果我们能将new出来不同地类地代码提取到一个专用的类中,在修改时将会有很大好处。
低耦合、高内聚,开放封闭原则(在很多工厂方法中不符合这一点)
描述: 通过传入参数,返回不同的对象。重点在于:将通过参数获得不同的对象的代码,从逻辑代码中提取出来,成为一个单独的类.
代码举例:
// 原来的代码
void buyCar() {
// 得到用户输入的车名
// 通过if语句new出相应的对象
Car car = null;
String name = scanner.nextLine();
if(name.equals("BW")) {
car = new BWCar();
} else if (name.equals("ABC")) {
car = new ABCCar();
} else {
}// 等等
// 走购买流程
}
// 注意:此时逻辑与新建对象混杂在一起.
// 当需要改变这段代码时,需要大费周章的找到所有类似逻辑
/**
* 提取对象.
*/
void buyCar() {
// 得到用户输入的车名
// 通过if语句new出相应的对象
// 可能会改变地逻辑被提取。
String name = scanner.nextLine();
Car car = CarFactory.newCarInstance(name);
// 走购买流程
}
// 将其提取到一个专用的类中:面向对象。
public class CarFactory {
static Car newCarInstance(String carName) {
// 通过if语句new出相应的对象
if(name.equals("BW")) {
car = new BWCar();
} else if (name.equals("ABC")) {
car = new ABCCar();
} else {
// 等等
}
}
} // Oh,别了吧,不就是换了个地方吗?
// 事实上,就是将代码从逻辑中提取到一个单独的类中。
// 但是当ABC车厂倒闭时,你只需要修改CarFactor即可,不再需要去逐个修改业务代码.
// 能有效地将与业务代码无关的部分分离出来,当需要修改车地类型(有的车厂倒闭了,新建了车厂)
// 此时不再修改任务业务类,只需要在CarFactory中进行简单修改,就可以保证代码地正确性.
PS : 我们在这里使用的是静态工厂,static关键字修饰了newInstance()方法。当然坏处就是无法通过继承的方式来改变这个方法。
总结:简单工厂并不算是一种模式,更像是一种编程习惯,但总的来说是一个很棒的编程习惯。
简单工厂中,我们通过参数控制返回的对象。但是这可不是一个好事情,通过参数控制很像面向过程的思维,我们应该使用对象,让对象去控制这个流程。
场景:在上面的代码中我们所有工厂都是通过简单的new新建一个车,但是事实上我们都知道一个牌子的车也是有三六九等的。
CarFactory改成一个抽象类,newCarInstance()改成抽象方法,由各个子类自己去实现,每个子类依然是一个简单工厂,这样每个工厂想生产什么就自己控制自己的代码。
PS : 这一下就从计划经济便成为宏观市场(通过类自己选择)微观计划(在类中依然是计划).
比如我现在想买一个BW出的至尊车。
void buyCar() {
// 通过多态,控制对应的工厂类.
Carfactory carFactory = new BWFactory();
String name = "至尊";
// 使用简单工厂.
carFactory.newInstance(name);
}
实际上,我们可以看到就是使用了面向对象的多态性,让对象帮我们做选择。
缺点:随着代码的发展,各种各样的产品的出现,其对应的工厂会越来越多,大众创业的情况下,将会出现非常多的牌子,造成类爆炸。
总结:可以理解工厂方法就是通过面向接口/多态性,来使子类做出自己独一无二的抉择.工厂方法对产品的扩展支持的很好,但工厂的扩展可能会造成工厂数量爆炸,难以管理。
工厂方法作为简单工厂的延申,成功解决了简单工厂的,
我们通过依赖倒置,让所有的工厂依赖CarFactory,让CarFactory生产汽车和公交车。
现在买车的逻辑有些变化:
我要买那个牌子的汽车? =====>CarFactory factory = new BWCarFactory();
我想买一辆便宜车. =====> CheapCar cheapCar = new CheapCar(factory);
我想买那个牌子的公交车=====>CarFactory factory = new ChinaBusFactory();
电动的就可以 ======>ElectricBus bus = new ElectricBus(factory);
在建造便宜车时,所有的零件都将来自BW工厂,最后生成一个价格低廉,性能较差的车辆,并且含有BW的商标。
好处很明显,对于各种各样的CarFactory,无论新增还是删除或者修改,业务代码都可以不用修改,也可以轻松的扩展出卡车工厂,三轮车工厂。
坏处就在于:产品的改变,如果现在需要生产一个"活动车",那么对于CarFactory接口,就需要做出改变,从而影响所有的CarFactory,比如我现在增加一个三轮车工厂,那么车工厂就需要增加生产三轮车的功能,那么之前所有CarFactory都必须增加一个生产三轮车的方法,那么他们仅仅只在方法中说:”抱歉,这个牌子不生产三轮车”。
很明显可以看出:抽象工厂是管理工厂时的工厂,但是其对产品的支持度较差。与工厂方法相反。
当你需要创建产品 家族和想让制造的相关产品集合起来时,你可以使用抽象工厂。
当你需要把业务代码中的“实例化的具体类”中解耦出来,或者你目前还不知道将来需要实例化那些具体类时,可以用工厂方法。只需要继承工厂成为一个子类,并实现对应的工厂就可以了。
当你单纯的只是想要把业务代码中的“实例化的具体类”中解耦出来,你可以使用简单工厂,当然简单工厂并不是一种模式,它更像一种编程习惯。