工厂方法简介:
工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
工厂方法模式是简单工厂模式的衍生(简单工厂模式请见连接:https://blog.csdn.net/qq_39241239/article/details/83276111),解决了许多简单工厂模式的问题。首先完全实现'开-闭 原则',实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。
工厂方法模式对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不再负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。
我们现在利用工厂模式模仿女娲造人的过程:
1.首先我们有一个AbstractHuman抽象类是人类的总称,其有三个实现类对应三个人种(白人、黄人、黑人)
2.我们还有一个抽象类AbstractHumanFactory,你可以把它看成一个八卦炉,其有三个实现类对应着三个八卦炉,分别用来产生白人、产生黄人、产生黑人。
3.我们定义的每个人都有两个方法:getColor(获得人的皮肤颜色)和talk(交谈)。
我们接下来看看代码实现:
package DesignPattern;
abstract class AbstractHuman {
abstract public void getColor();
abstract public void talk();
}
class WhiteHuman extends AbstractHuman {
public void getColor() {
System.out.println("白色人种的皮肤颜色是白色的");
}
public void talk() {
System.out.println("白色人种会说话,一般都是单音节");
}
}
class YellowHuman extends AbstractHuman {
public void getColor() {
System.out.println("黄色人种的皮肤颜色是黄色的");
}
public void talk() {
System.out.println("黄色人种会说话,一般都是双音节");
}
}
class BlackHuman extends AbstractHuman {
public void getColor() {
System.out.println("黑色人种的皮肤颜色是黑色的");
}
public void talk() {
System.out.println("黑色人种会说话,但是一般人听不懂");
}
}
abstract class AbstractHumanFactory {
// 八卦炉可以产生人类
public abstract AbstractHuman createHuman();
}
class WhiteFactory extends AbstractHumanFactory {
public AbstractHuman createHuman() {
return new WhiteHuman();
}
}
class YellowFactory extends AbstractHumanFactory {
public AbstractHuman createHuman() {
return new YellowHuman();
}
}
class BlackFactory extends AbstractHumanFactory {
public AbstractHuman createHuman() {
return new BlackHuman();
}
}
//女娲要开始造人了
public class NvWa {
public static void main(String[] args) {
System.out.println("--造出的第一批人是白色人种--");
AbstractHuman whiteHuman = (new WhiteFactory()).createHuman();
whiteHuman.getColor();
System.out.println("--造出的第二批人是黄色人种--");
AbstractHuman yellowHuman = (new YellowFactory()).createHuman();
yellowHuman.getColor();
System.out.println("--造出的第三批人是黑色人种--\"");
AbstractHuman blackHuman = (new BlackFactory()).createHuman();
blackHuman.getColor();
}
}
工厂方法模式
抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。就是上例中的AbstractHumanFactory,也是下面类图中的AbstractFactory。
具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。就是上例中的WhiteFactory、YellowFactory、BlackFactory。也是下面类图的ConcreteFactory1、ConcreteFactory2等等
抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。就是上例中的AbstractHuman,也是下面类图的AbstractProduct。
具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。就是上例中的WhiteHuman、YellowHuman、BlackHuman。
来用类图来清晰的表示下的它们之间的关系:
优点
1.更符合开-闭原则,新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可。简单工厂模式需要修改工厂类的判断逻辑
2.符合单一职责原则,每个具体工厂类只负责创建对应的产品
3.简单工厂中的工厂类存在复杂的switch逻辑判断
4.不使用静态工厂方法,可以形成基于继承的等级结构。简单工厂模式的工厂类使用静态工厂方法
总结:工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。
缺点
1.添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
2.由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
3.虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
4.一个具体工厂只能创建一种具体产品
应用场景
1.当一个类不知道它所需要的对象的类时 。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可;
2.当一个类希望通过其子类来指定创建对象时 。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
3.将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。