一、介绍,定义
工厂方法模式(Pattern:Factory Method)属于创建型模式,其意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,将核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
定义一个用于创建对象的接口,让子类决定实例化哪个类。
二、使用场景
①当需要一个对象时,我们不需要知道该对象所对应的具体类,只要知道哪个具体工厂可以生成该对象,实例化这个具体工厂即可创建该对象。
②类的数目不固定,随时有新的子类增加进来,或者是还不知道将来需要实例化哪些具体类。
③定义一个创建对象接口,由子类决定要实例化的类是哪一个;客户端可以动态地指定工厂子类创建具体产品。
在任何需要生产复杂对象的地方,都可以使用。
复杂对象适合使用工厂方法模式,用new就可以创建的对象无需使用工厂模式。
三、工厂方法模式UML类图
6.png 7.png(1)抽象工厂角色[Creator]:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
(2)具体工厂角色[Concrete Creator]:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。
(3)抽象产品角色[Product]:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
(4)具体产品角色[Concrete Product]:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
1)设计原则:
①依赖倒置原则:要依赖抽象,不要依赖具体类。
用依赖倒置原则设计的系统,使得对象的实现从使用中解耦,对象的使用是在Creator,实现却在ConcreteCreator中,Creator只有Product的引用,Creator与ConcreteProduct松耦合,这种设计拥有很强的扩展性、弹性和可维护性。
通用模式代码:
public abstract class Product{
//由具体产品实现的抽象方法
public abstract void mothod()
}
public class ConcreteProductA extends Product{
@Override
public void method(){
System.out.println("我是A");
}
}
public class ConcreteProductB extends Product{
@Override
public void method(){
System.out.println("我是B");
}
}
public abstract class Factory{
//由子类实现具体生产什么 return具体产品对象
public abstract Product createProduct();
}
public class ConcreteFactory extends Factory{
@Override
public Product createProduct(){
return new ConcreteProductA();
}
}
public class Client{
public static void main(String [] args){
Factory factory = new ConcreteFactory();
Product p = factory.createProduct();
p.method();
}
}
这里我们在Client类中声场了一个ConcreteProductA 对象,如果想得到ConcreteProductB的实例,更改ConcreteFactory 逻辑即可
public class ConcreteFactory extends Factory{
@Override
public Product createProduct(){
return new ConcreteProductB();
//return new ConcreteProductA();
}
}
有时也利用反射方式更简洁的来生产具体的产品对象,此时需要传入一个Class类来决定是哪一个产品
public abstract class Factory{
//由子类实现具体生产什么 return具体产品对象
public abstract <T extends Product> T createProduct(Class<T> clz);
}
public class ConcreteFactory extends Factory{
@Override
public <T extends Product> T createProduct(Class<T> clz){
Product p = null;
try{
p = (Product)Class.forName(clz.getName()).newInstance();
}catch(Exception e){
e.printStackTrace();
}
return (T)p;
}
}
public class Client{
public static void main(String [] args){
Factory factory = new ConcreteFactory();
Product p = factory.createProduct(ConcreteProductB.class);
p.method();
}
}
上面这种方式比较简洁,当然也可以尝试为每一个产品都定义具体的工厂类,各司其职
public class ConcreteFactoryA extends Factory{
@Override
public Product createProduct(){
return new ConcreteProductA();
}
}
public class ConcreteFactoryB extends Factory{
@Override
public Product createProduct(){
return new ConcreteProductB();
}
}
public class Client{
public static void main(String [] args){
Factory factory = new ConcreteFactoryA();
Product pA = factoryA.createProduct();
pA.method();
Factory factoryB = new ConcreteFactoryB();
Product pB = factoryB.createProduct();
pB.method();
}
}
像这样拥有多个工厂的方式称为多工厂方法模式,当我们的工厂只有一个,我们将对应的工厂方法改为静态方法,称为简单工厂模式或者静态工厂模式。
四、工厂方法模式简单实现
小李是一家汽车厂的厂长,对他来说,组装汽车没什么好神秘的,无非就是将一些进口的核心部件,比如发动机和一些国内的零部件组装起来,小李的汽车厂主要是组装某款SUV车型,比如Q3,Q5,Q7,对于这类车型来说,内部结构差异并不是很大,因此,对小李来说一条生产线足以应付这3种车型,对于该类生产线小李提供了一个抽象类定义:
public abstract class AudiFactory{
/**
*某车型的工厂方法
*@param ljz 具体的SUV型号
*@return 具体型号的SUV车对象
*/
public abstract<T extends AudioCar> T creatAudiCar(Class<T> clz) ;
}
由于三种车差异不大,所以一条生产线即可。
public class AudiCarFactory extends AudiFactory{
@Override
public abstract<T extends AudiCar> T creatAudiCar(Class<T> clz) {
AudioCar car=null;
try{
car=(AudioCar)Class.forname(clz.getName()).newInstance();
}catch(Exception e){
e.printStackTrace();
}
return (T)car;
}
}
对于这3种车型,除了一些车都有的基本特性外,还提供自动巡航功能,类似无人驾驶,这些功能小李用一个抽象的基类来声明:
//汽车的抽象产品类
public abstract class AudiCar{
//定义汽车的一个行为方法,车可以启动开走
public abstract void drive();
//定义汽车的一个行为方法,车可以自动巡航
public abstract void selfNavigation();
}
//接着就是生产每一种具体的车型了:
public class AudiQ3 extends AudiCar{
@Override
public void drive(){
System.out.println("Q3启动了");
}
@Override
public void selfNavigation(){
System.out.println("Q3开始自动巡航");
}
}
public class AudiQ5 extends AudiCar{
@Override
public void drive(){
System.out.println("Q5启动了");
}
@Override
public void selfNavigation(){
System.out.println("Q5开始自动巡航");
}
}
public class AudiQ7 extends AudiCar{
@Override
public void drive(){
System.out.println("Q7启动了");
}
@Override
public void selfNavigation(){
System.out.println("Q7开始自动巡航");
}
}
最后我们将各个类组装起来形成一条完整的流水线:
public class Client{
public static void main(String[] args){
//构造一个汽车的工厂对象
AudiFactory factory=new AudiCarFactory();
//生产Q3并启动
AudiQ3 audiQ3=factory.createAudioCar(AudiQ3.class);
audiQ3.drive();
audiQ3.selfNavigation();
//生产Q5并启动
AudiQ5 audiQ5=factory.createAudiCar(AudiQ5.class);
audiQ5.drive();
audiQ5.selfNavigation();
//生产Q7并启动
AudiQ7 audiQ7=factory.createAudiCar(AudiQ7.class);
audiQ7.drive();
audiQ7.selfNavigation();
}
}
输出结果如下:
Q3启动啦
Q3开始自动巡航!
Q5启动啦
Q5开始自动巡航!
Q7启动啦
Q7开始自动巡航!
五、工厂方法模式的优缺点:
(1)优点:
①符合开闭原则,具有很强的的扩展性、弹性和可维护性。扩展时只要添加一个ConcreteCreator,而无须修改原有的ConcreteCreator,因此维护性也好。解决了简单工厂对修改开放的问题。
②使用了依赖倒置原则,依赖抽象而不是具体,使用(客户)和实现(具体类)松耦合。
③客户只需要知道所需产品的具体工厂,而无须知道具体工厂的创建产品的过程,甚至不需要知道具体产品的类名。
(2)缺点:
①一个具体产品对应一个类,当具体产品过多时会使系统类的数目过多,增加系统复杂度。
②每增加一个产品时,都需要一个具体类和一个具体创建者,使得类的个数成倍增加,导致系统类数目过多,复杂性增加。
③对简单工厂,增加功能修改的是工厂类;对工厂方法,增加功能修改的是客户端。
网友评论