工厂方法(Factory Method)
简单工厂、工厂方法、抽象工厂的区别
简单工厂使用举例
如果说我们有一个父类“交通工具”,它有两个子类“汽车”和“自行车”,我们现在只需要一个工厂负责根据不同的条件创建不同的子类并返回,比如如果条件为“雨天”则创建汽车,条件为“晴天”则创建自行车,这个工厂就是简单工厂,通过调用它的 create 方法,根据方法的参数,创建某一种父类的子类,并将对象返回,create 的调用方会用父类接口接收 create 返回的具体子类。
简单工厂好处
(1)客户端不需要掌握所有子类类型,无需编写创建具体子类的逻辑代码,只用传入参数,工厂就创建相应子类返回给客户端,客户端用父类引用调用子类的不同方法。
(2)当子类的创建逻辑发生修改、子类类型新增时,由于客户端与子类创建逻辑解耦,因此不需要修改客户端端代码(当有多个客户端时,减少大量的代码修改工作,只需修改一个工厂类中的代码即可)
工厂方法
工厂方法和简单工厂的使用场景是一样的,都是用于为客户端创建单一子类对象,只不过简单工厂只有一个工厂类,工厂类中有一个 create 方法,其中利用逻辑判断需要为客户端创建哪种子类(客户端调用:Factory f=new Factory(),f.create())。而工厂方法有一个抽象工厂接口(定义一个 factoryMethod),不同的工厂子类负责创建不同的子类(具体的子类创建逻辑由不同工厂负责撰写),客户端调用:Factory f=new Factory1(),f.create())
抽象工厂使用举例
如果说我们有一个父类“汽车”,他有两个子类“奥迪”和“BYD”,而“奥迪”又包含对象成员“轮子”、“车灯”,奔驰也包含对象成员“轮子”、“车灯”,我们最终的目的是创建某种汽车的某个对象参数,比如我现在要得到一种车灯,并输出它的亮度,我输入的条件是“晚上”,我们现在需要工厂依据我们输入的条件“晚上”,创建奥迪的车灯(显然奥迪的车灯更亮嘛。。。),也就是说,客户端首先得到工厂的子类奥迪工厂(不论是奥迪工厂还是 BYD 工厂,他们都包含创建具体车灯的createLamp、创建具体轮子的createWheel),然后调用奥迪工厂的 createLamp 方法获取车灯对象AodiLamp,然后调用AodiLamp 的 getBrightness 方法输出亮度。等等!这里好像有一个问题呀,我们既然说“工厂向用户屏蔽对象创建的逻辑以及具体对象的类型”,那么客户现在应该是不知道车灯的具体类型的呀,而是应该用 Lamp 父类去接收createLamp 返回的具体子类。所以,我们不仅需要(1)汽车抽象工厂(定义具体工厂需要实现的接口:createLamp、createWheel)、(2)具体工厂(继承抽象工厂,实现createLamp、createWheel接口——创建相应汽车的具体对象)、(3)抽象产品(Lamp、Wheel,客户端利用该抽象类型指向工厂创建出的具体类型,客户端不需要知道具体的产品类型是什么)、(4)具体产品(AodiLamp、BYDLamp、AodiWheel、BYDWheel)
抽象工厂好处
(1)当子类又包含多种对象成员,并且不同子类的对象成员具有相同的父类(AodiLamp、BYDLamp的父类 Lamp),当客户端向创建某种子类的某对象成员时,客户端首先获取具体工厂类(无需知道具体工厂类型,利用抽象工厂引用指向具体工厂),然后调用其创建某种对象成员的方法(客户端不需要知道对象成员的具体类型,客户端只利用 Lamp 抽象类型作为引用即可,由工厂的创建对象方法返回具体是 AodiLamp 还是 BYDLamp)
(2)适用于创建某系列(版本)中的某种产品,即当前有系列1、系列2、后续还可能创建序列3等等,系列1包含对象成员(A1、B1、C1),系列2包含对象成员(A2、B2、C2),A1和 A2具有相同的父类。客户端需求为获取某系列的 A ,然后调用 A 的相应方法时,利用工厂方法不仅能够屏蔽对象创建的逻辑处理细节,而且当客户端需要创建某一系列的多种对象成员时,可以仅修改具体工厂类型,而改变后续所有的对象成员。
//抽象工厂 interface Factory { A createA(){}; B createB(){}; } //具体工厂1 class Factory1 implements Factory{ A createA(){ return new A1(); } B createB(){ return new B(); } } //具体工厂2 class Factory2 implements Factory{ A createA(){ return new A2(); } B createB(){ return new B2(); } } //抽象产品 class A{ say(){ } } //具体产品1 class A1{ say(){ system.out.println("我是 A1"); } } //具体产品2 class A2{ say(){ system.out.println("我是 A2"); } } class B{ say(){ } } class B1{ say(){ system.out.println("我是 B1"); } } class B2{ say(){ system.out.println("我是 B2"); } } class Client{ public static void main(String[] args){ Factory f=new Factory1(); //或者将这里的创建逻辑也用简单工厂的方式实现 A a=f.createA(); a.say(); B b=f.createB(); b.say(); //当我们的需求发生改变,或者新增系列 factory3...时,不需要修改后面四行的逻辑,只需要修改第一行——Factory f=new Factory3();即可Factory3需要 implements Factory 接口,Factory3中的 A3需要implements A,B3需要implements B } }
Intent
定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。
Class Diagram
在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。
下图中,Factory 有一个 doSomething() 方法,这个方法需要用到一个产品对象,这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。
Implementation
public abstract class Factory {
abstract public Product factoryMethod();
public void doSomething() {
Product product = factoryMethod();
// do something with the product
}
}
public class ConcreteFactory extends Factory {
public Product factoryMethod() {
return new ConcreteProduct();
}
}
public class ConcreteFactory1 extends Factory {
public Product factoryMethod() {
return new ConcreteProduct1();
}
}
public class ConcreteFactory2 extends Factory {
public Product factoryMethod() {
return new ConcreteProduct2();
}
}