一、简单工厂模式
一个栗子:
我喜欢吃面条,抽象一个面条基类,(接口也可以),这是产品的抽象类。
public abstract class INoodles {
/**
* 描述每种面条啥样的
*/
public abstract void desc();
先来一份兰州拉面(具体的产品类):
public class LzNoodles extends INoodles {
@Override
public void desc() {
System.out.println("兰州拉面 上海的好贵 家里才5 6块钱一碗");
}
}
程序员加班必备也要吃泡面(具体的产品类):
public class PaoNoodles extends INoodles {
@Override
public void desc() {
System.out.println("泡面好吃 可不要贪杯");
}
还有我最爱吃的家乡的干扣面(具体的产品类):
public class GankouNoodles extends INoodles {
@Override
public void desc() {
System.out.println("还是家里的干扣面好吃 6块一碗");
}
}
准备工作做完了,我们来到一家“简单面馆”(简单工厂类),菜单如下:
public class SimpleNoodlesFactory {
public static final int TYPE_LZ = 1;//兰州拉面
public static final int TYPE_PM = 2;//泡面
public static final int TYPE_GK = 3;//干扣面
public static INoodles createNoodles(int type) {
switch (type) {
case TYPE_LZ:
return new LzNoodles();
case TYPE_PM:
return new PaoNoodles();
case TYPE_GK:
default:
return new GankouNoodles();
}
}
}
简单面馆就提供三种面条(产品),你说你要啥,他就给你啥。这里我点了一份干扣面:
/**
* 简单工厂模式
*/
INoodles noodles = SimpleNoodlesFactory.createNoodles(SimpleNoodlesFactory.TYPE_GK);
noodles.desc();
输出:
还是家里的干扣面好吃 6块一碗
特点
1 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
2 create()方法通常是静态的,所以也称之为静态工厂。
缺点
1 扩展性差(我想增加一种面条,除了新增一个面条产品类,还需要修改工厂类方法)
2 不同的产品需要不同额外参数的时候 不支持。
简单工厂实例
package demo1;
public abstract class Operation {
private double numberA = 0;
private double numberB = 0;
public void setNumberA(double numberA) {
this.numberA = numberA;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
public double getNumberA() {
return numberA;
}
public double getNumberB() {
return numberB;
}
public double getResult() {
double result = 0;
return result;
}
}
package demo1;
public class OperationAdd extends Operation {
@Override
public double getResult() {
double result = 0;
result = super.getNumberA() + super.getNumberB();
return result;
}
}
package demo1;
public class OperationSub extends Operation {
@Override
public double getResult() {
double result = 0;
result = super.getNumberA() - super.getNumberB();
return result;
}
}
package demo1;
public class OperationMul extends Operation {
@Override
public double getResult() {
double result = 0;
result = super.getNumberA() * super.getNumberB();
return result;
}
}
package demo1;
public class OperationDiv extends Operation {
@Override
public double getResult() {
double result = 0;
if (super.getNumberB() == 0)
throw new ArithmeticException("除数不能为0.");
result = super.getNumberA() / super.getNumberB();
return result;
}
}
package demo1;
public class OperationFactory {
public static Operation createOperate(String operate) {
Operation oper = null;
switch (operate) {
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
}
package demo1;
public class Demo1 {
public static void main(String[] args) {
Operation oper;
oper = OperationFactory.createOperate("/");
oper.setNumberA(10);
oper.setNumberB(7);
double result = oper.getResult();
System.out.println(result);
}
}
2.工厂方法
1.1 定义
工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。
1.2 主要作用
将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一个类。
1.3 解决的问题
工厂一旦需要生产新产品就需要修改工厂类的方法逻辑,违背了“开放 - 关闭原则
- 即简单工厂模式的缺点
- 之所以可以解决简单工厂的问题,是因为工厂方法模式把具体产品的创建推迟到工厂类的子类(具体工厂)中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式在添加新产品的时候就不修改工厂类逻辑而是添加新的工厂子类,符合开放封闭原则,克服了简单工厂模式中缺点
2.1 UML类图
2.2 模式组成
组成(角色) | 关系 | 作用 |
---|---|---|
抽象产品(Product) | 具体产品的父类 | 描述具体产品的公共接口 |
具体产品(Concrete Product) | 抽象产品的子类;工厂类创建的目标类 | 描述生产的具体产品 |
抽象工厂(Creator) | 具体工厂的父类 | 描述具体工厂的公共接口 |
具体工厂(Concrete Creator) | 抽象工厂的子类;被外界调用 | 描述具体工厂;实现FactoryMethod工厂方法创建产品的实例 |
2.3 使用步骤
步骤1: 创建抽象工厂类,定义具体工厂的公共接口;
步骤2: 创建抽象产品类 ,定义具体产品的公共接口;
步骤3: 创建具体产品类(继承抽象产品类) & 定义生产的具体产品;
步骤4:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
步骤5:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
接下来我用一个实例来对工厂方法模式进行更深一步的介绍。
3.1 实例概况
- 背景:小成有一间塑料加工厂(仅生产A类产品);随着客户需求的变化,客户需要生产B类产品;
- 冲突:改变原有塑料加工厂的配置和变化非常困难,假设下一次客户需要再发生变化,再次改变将增大非常大的成本;
- 解决方案:小成决定置办塑料分厂B来生产B类产品;
即工厂方法模式
3.2 使用步骤
步骤1: 创建抽象工厂类,定义具体工厂的公共接口
abstract class Factory{
public abstract Product Manufacture();
}
步骤2: 创建抽象产品类 ,定义具体产品的公共接口;
abstract class Product{
public abstract void Show();
}
步骤3: 创建具体产品类(继承抽象产品类), 定义生产的具体产品;
//具体产品A类
class ProductA extends Product{
@Override
public void Show() {
System.out.println("生产出了产品A");
}
}
//具体产品B类
class ProductB extends Product{
@Override
public void Show() {
System.out.println("生产出了产品B");
}
}
步骤4:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
//工厂A类 - 生产A类产品
class FactoryA extends Factory{
@Override
public Product Manufacture() {
return new ProductA();
}
}
//工厂B类 - 生产B类产品
class FactoryB extends Factory{
@Override
public Product Manufacture() {
return new ProductB();
}
}
步骤5:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
//生产工作流程
public class FactoryPattern {
public static void main(String[] args){
//客户要产品A
FactoryA mFactoryA = new FactoryA();
mFactoryA.Manufacture().Show();
//客户要产品B
FactoryB mFactoryB = new FactoryB();
mFactoryB.Manufacture().Show();
}
}
结果:
生产出了产品A
生产出了产品C
4. 优点
-
更符合开-闭原则
新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可简单工厂模式需要修改工厂类的判断逻辑
-
符合单一职责原则
每个具体工厂类只负责创建对应的产品简单工厂中的工厂类存在复杂的switch逻辑判断
-
不使用静态工厂方法,可以形成基于继承的等级结构。
简单工厂模式的工厂类使用静态工厂方法
总结:工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。
- 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
- 虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
- 一个具体工厂只能创建一种具体产品
在了解了优缺点后,我总结了工厂方法模式的应用场景:
- 当一个类不知道它所需要的对象的类时
在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可; - 当一个类希望通过其子类来指定创建对象时
在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。 - 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。
三. 抽象工厂模式(Abstract Factory)
抽象工厂模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了开闭原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
代码示例:
抽象工厂模式与工厂方法模式的区别
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。我们依然拿生产汽车的例子来说明他们之间的区别。
-
interface IProduct1 { public void show(); } interface IProduct2 { public void show(); } class Product1 implements IProduct1 { public void show() { System.out.println("这是1型产品"); } } class Product2 implements IProduct2 { public void show() { System.out.println("这是2型产品"); } } interface IFactory { public IProduct1 createProduct1(); public IProduct2 createProduct2(); } class Factory implements IFactory{ public IProduct1 createProduct1() { return new Product1(); } public IProduct2 createProduct2() { return new Product2(); } } public class Client { public static void main(String[] args){ IFactory factory = new Factory(); factory.createProduct1().show(); factory.createProduct2().show(); } }