概述
工厂模式主要是为创建对象提供过渡性接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
工厂模式可以分成三类:
1:简单工厂模式(Simple Factory):不利于生产系列产品,使用场景要求简单;
2:工厂方法模式(Factory Method):又称多形性工厂;
3:抽象工厂模式(Abstract Factory):又称工具箱,产生产品族,但不利于产生新的产品;
简单工厂模式
简单工厂模式就是工厂对象根据传入的参数,动态的决定创建哪一种产品类的实例,而这些产品类继承一个父类或者接口。简单工厂模式属于创建型模式,又叫静态工厂方法(static factory method)。
UML类图如下:
在上面UML类图中包含以下角色:
1:工厂类角色(Factory):这是简单工厂模式的核心,由它负责创建所有实例的逻辑。工厂对象用来被外界调用,根据传入的参数来决定创建哪一个产品对象。
2:抽象产品角色:使所有具体产品对象的父类,由它来定义所有具体产品的公共接口。在java中由接口或者抽象类来实现。
3:具体产品角色:是简单工厂模式创建的目标,所有创建的对象都是具体某个产品类的实例。
代码示例:
interface Product {
public void method();
}
class ProductA implements Product {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("i am product a");
}
}
class ProductB implements Product {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("i am product b");
}
}
public class Factory {
public Product create(String type) {
Product product = null;
if (type.equals("a")) {
product = new ProductA();
} else if (type.equals("b")) {
product = new ProductB();
}
return product;
}
public static void main(String arg[]) {
Factory factory = new Factory();
Product producta = factory.create("a");
producta.method();
Product productb = factory.create("b");
productb.method();
}
}
优点:
客户类和工厂类分开,用户只需要向工厂请求即可生成对应的产品。外界不需要关注对象创建逻辑,产品对象具体的创建过程由工厂来实现,外界只需要给定信息就能决定创建哪个产品对象。这样明确了各自的职责,有利于整个软件体系结构的优化。
缺点:
违反了高内聚责任分配原则,将所有的创建逻辑都集中在工厂类身上。如果需要添加新的产品类,则需要修改工厂类。当产品不断增多,工厂类对产品类型的判断就非常多,造成逻辑过于复杂化,对于系统的扩展和维护不利。
使用场景:
工厂类创建的产品对象比较少,外界只需要传入工厂类参数来获得产品对象,对产品创建过程不关心。简单工厂模式很容易违反高内聚责任分配原则,所以只在一些很简单的情况下使用。
工厂方法模式
如上所述,简单工厂模式应用在产品对象比较少,对产品创建过程不关心的场景下。当产品种类不断增多时,就会不断去修改工厂类,造成工厂类中判断逻辑复杂,使得对系统维护和扩展不便。为了避免这样的缺点,又从简单工厂模式中衍生出了工厂方法模式,就是让里面的核心工厂类不再负责具体的产品创建,而是抽象工厂的角色,仅仅定义子类工厂必须实现的接口,这样的好处是可以使系统在不修改具体工厂类的方式下引进新的产品。
有一个抽象的Factory类(可以是抽象类和接口),这个类不再负责具体的产品生产,而只是制定一些规范,
具体的生产工作由其子类完成。在这个模式中,工厂类和产品类可以一次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产具体的产品。工厂方法模式的核心是对工厂也进行抽象。
UML类图如下:
在上面UML图中包含以下角色:
抽象工厂(interface Factory)角色:工厂方法模式的核心,主要定义了具体工厂子类必须要实现的接口,并且所有创建对象的工厂类都必须实现该方法,与应用程序无关。
具体工厂角色:实现抽象工厂的具体工厂类,包含与应用程序密切相关的逻辑,受到应用程序的调用以创建产品对象。
抽象产品角色:具体产品对象的共同父类,由它来定义所有产品的共同接口。
具体产品角色:创建的对象都是某个具体产品类的实例。
代码示例:
interface Product {
public void method();
}
class ProductA implements Product {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("i am product a");
}
}
class ProductB implements Product {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("i am product b");
}
}
interface Factory {
public Product create();
}
class Factorya implements Factory {
@Override
public Product create() {
// TODO Auto-generated method stub
Product a = new ProductA();
return a;
}
}
class Factoryb implements Factory {
@Override
public Product create() {
// TODO Auto-generated method stub
Product b = new ProductB();
return b;
}
}
public class MainTest {
public static void main(String arg[]) {
Factory fa = new Factorya();
Product pa = fa.create();
pa.method();
Factory fb = new Factoryb();
Product pb = fb.create();
pb.method();
}
}
优点:
避免了简单工厂模式中出现的问题。完全符合“开闭原则”,具有可扩展性,层次结构更复杂,可以应付产品结果更复杂的场合。工厂方法模式是典型的解耦框架,高层模块只需要知道产品的抽象类,其他实现类都不需要关心,只依赖产品的抽象,符合依赖倒置原则。
缺点:
抽象出了一个抽象工厂,增加了一个具体工厂类,会提高系统的复杂度。所以对于一些复杂的创建过程使用工厂方法模式才比较合适。
抽象工厂模式
抽象工厂模式是工厂方法模式的升级版本,主要是引入了一个产品族的概念,将针对单一产品升级到了针对多个产品品种的产品分类。
UML类图如下:
上面的UML图中相较于工厂方法模式中增加了一个抽象产品和具体产品角色。抽象工厂模式核心在于有了多个产品族。如上,ProductA1和ProductA2就是属于一个产品族。ProductA1和ProductB1分别属于两个不同的产品族,上面UML有两个产品族。
有几个抽象产品类就有几个产品族,有几个产品族,在工厂中就有几个创建方法。继承于同一个抽象产品类的属于不同的产品等级。
ProductA1和ProductA2就是两个产品等级,ProductA1和ProductB1属于同一个产品等级。
有几个产品等级,就有几个实现工厂类,在每个工厂类中,实现了不同的产品族的创建方法。
代码示例:
interface ProductA {
public void method();
}
class ProductA1 implements ProductA {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("i am product a1");
}
}
class ProductA2 implements ProductA {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("i am product a2");
}
}
interface ProductB {
public void method();
}
class ProductB1 implements ProductB {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("i am product b1");
}
}
class ProductB2 implements ProductB {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("i am product b2");
}
}
interface Factory {
public ProductA createProductA();
public ProductB createProductB();
}
class Factory1 implements Factory {
@Override
public ProductA createProductA() {
// TODO Auto-generated method stub
ProductA pa1 = new ProductA1();
return pa1;
}
@Override
public ProductB createProductB() {
// TODO Auto-generated method stub
ProductB pb1 = new ProductB1();
return pb1;
}
}
class Factory2 implements Factory {
@Override
public ProductA createProductA() {
// TODO Auto-generated method stub
ProductA pa2 = new ProductA2();
return pa2;
}
@Override
public ProductB createProductB() {
// TODO Auto-generated method stub
ProductB pb2 = new ProductB2();
return pb2;
}
}
public class MainTest {
public static void main(String arg[]) {
Factory factory1 = new Factory1();
ProductA productA1 = factory1.createProductA();
ProductB productB1 = factory1.createProductB();
productA1.method();
productB1.method();
Factory factory2 = new Factory2();
ProductA productA2 = factory2.createProductA();
ProductB productB2 = factory2.createProductB();
productA2.method();
productB2.method();
}
}
优点:
上层模块只需要知道生产相应产品的工厂类是谁,就能由工厂创建相应的产品对象,而它不用关心具体产品生产过程,只依赖抽象产品,符合依赖倒置原则。不同产品族之间的约束放在工厂类中来实现,不对外公开,封装性好。相较于工厂方法模式,可以应付产品更复杂的场合。
缺点:
增加一个产品族时,即相当于增加一个抽象产品,需要修改大量的其它实现工厂,在产品族层面扩展性不好。
参考:
http://tianweili.github.io/blog/2015/03/08/simple-factory-pattern/
http://tianweili.github.io/blog/2015/03/09/factory-method-pattern/
http://tianweili.github.io/blog/2015/03/11/abstract-factory-pattern/