工厂方法模式,又称“工厂模式”、“虚拟构造器”、“多态工厂模式”,属于类创建型模式。
在基类(抽象工厂类)中定义创建对象的一个公共接口,让其子类(具体工厂类)决定实例化哪一个类。工厂方法模式让一个具体产品类的实例化延迟到其子类(具体工厂类)中进行。
工厂方法模式包含了如下 4 种角色(含完整示例代码)
一个笔记本制造商拥有3个子工厂,每个子工厂只做一种品牌的笔记本,而核心总部作为核心工厂,只负责制定规范,规定每个子工厂需要完成的所有任务。
1.抽象工厂(Creator)
抽象工厂类将具体工厂类的实现细节隐藏起来,如果具体工厂类发生了修改,对于外部客户端的调用没有任何影响。因为抽象工厂类中给出了抽象方法,任何具体工厂类都必须继承或实现抽象工厂类(或工厂接口)。
package com.com.abstract_Factory;
import com.abstract_product.Laptop;
public interface LaptopFactory {
//生产笔记本电脑
public Laptop produce();
//售后服务
public void aftersalesservice();
}
2.具体工厂(Concrete Creator)
具体工厂类是依赖于具体的产品的,每一个产品的进行实例化的方式的改变,都将对其对应的具体工厂类产生影响。但具体工厂类发生的改变,是不会对抽象工厂类产生影响的,因为具体工厂类遵循了抽象工厂方法的定义标准。
package com.concrete_factory;
import com.abstract_product.Laptop;
import com.com.abstract_Factory.LaptopFactory;
import com.concrete_product.Acerlaptop;
public class Acerfactory implements LaptopFactory {
@Override
public Laptop produce() {
return new Acerlaptop();
}
@Override
public void aftersalesservice() {
System.out.println("欢迎使用宏碁售后服务热线。");
}
}
package com.concrete_factory;
import com.abstract_product.Laptop;
import com.com.abstract_Factory.LaptopFactory;
import com.concrete_product.Delllaptop;
public class DellFactory implements LaptopFactory {
@Override
public Laptop produce() {
return new Delllaptop();
}
@Override
public void aftersalesservice() {
System.out.println("欢迎使用戴尔售后服务热线。");
}
}
package com.concrete_factory;
import com.abstract_product.Laptop;
import com.com.abstract_Factory.LaptopFactory;
import com.concrete_product.Lenovolaptop;
public class Lenovofactory implements LaptopFactory {
@Override
public Laptop produce() {
return new Lenovolaptop();
}
@Override
public void aftersalesservice() {
System.out.println("欢迎使用联想售后服务热线。");
}
}
3.抽象产品(Product)
抽象产品类向任何发出产品对象创建请求的客户端屏蔽了所有产品的细节,也就是说,通过抽象工厂类提取所有产品对象所共有的“特性”,对每一个客户端可见的信息都是没有任何差别的。抽象产品类可以用抽象类或接口表示。
package com.abstract_product;
public abstract class Laptop {
//笔记本电脑的品牌
private String brand;
public Laptop(String str) {
this.brand = str;
}
abstract public String getId();
public void getDescription() {
System.out.println("This is a " + brand + " Laptop.");
}
}
4.具体产品(Concrete Product)
具体产品类具有产品对象的数据和服务(方法),客户端通过获取到所需要的产品对象,来完成特定的业务流程。具体产品类的创建方式,对于具体工厂类来说是可见的。具体工厂类只需要知道具体产品类的创建方式,并且该具体产品类是继承(或实现)抽象工厂类的抽象方法中所要求的抽象产品类类型。
package com.concrete_product;
import com.abstract_product.Laptop;
public class Acerlaptop extends Laptop {
private static final String brand = "Acer";
protected static int initId;
public Acerlaptop(){
super(Acerlaptop.brand);
initId = 100;
}
@Override
public String getId() {
return "Acer --> " + (initId ++) ;
}
}
ackage com.concrete_product;
import com.abstract_product.Laptop;
public class Delllaptop extends Laptop {
private static final String brand = "DELL";
protected static int initId;
public Delllaptop(){
super(Delllaptop.brand);
initId = 300;
}
@Override
public String getId() {
return "DELL --> " + (initId ++) ;
}
}
import com.abstract_product.Laptop;
public class Lenovolaptop extends Laptop {
private static final String brand = "Lenovo";
protected static int initId;
public Lenovolaptop(){
super(Lenovolaptop.brand);
initId = 200;
}
@Override
public String getId() {
return "Acer --> " + (initId ++) ;
}
}
客户端测试类:
package com.test;
import com.abstract_product.Laptop;
import com.com.abstract_Factory.LaptopFactory;
import com.concrete_factory.Acerfactory;
public class Test {
public static void main(String[] args) {
LaptopFactory laptopFactory = new Acerfactory();
Laptop laptop = laptopFactory.produce();
laptop.getDescription();
laptop.getDescription();
System.out.println(laptop.getId());
}
}
工厂方法模式的优点:
1.在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户端隐藏了其具体产品类的实例化过程细节,用户只需要关心所需产品对应的工厂,无需关心具体产品对象的创建细节,甚至无需知道具体产品类的类名。
2.基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂能够自主确定创建何种产品对象,而关于如何创建这个对象的细节则完全封装在具体工厂内部。
3.在系统中加入新产品时,无需修改抽象工厂类和抽象产品类提供的接口,无需修改客户端,而只需要添加一个新的具体工厂类和具体产品类即可。这样子,系统的可拓展性完全符合“开闭原则”。
工厂方法模式的缺点:
1.在添加新产品时,需要添加新的具体产品类和具体工厂类,系统中类的个数成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,开销增大。
2.由于考虑到系统的可拓展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度。
适用情况:
1.在编码时无法预见要创建哪一种具体产品类的实例;
2.一个类使用它的子类创建对象;
3.开发人员不希望创建了哪个类的实例以及如何创建实例的信息被暴露给外部程序。