工厂设计模式,顾名思义,就是用来生产对象的,在Java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则(一个好的软件实体应该对扩展开放,对修改关闭);另外,如果创建一个类的过程过于复杂,如需要传递过多的构造方法参数等,那么创建对象将会变得非常麻烦,并且会与其他业务类进行耦合。当这个类发生修改时,就需要在任何引用该类的源代码处进行修改;后期维护成本将会变得巨大;
如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的;
工厂设计模式分为三种,分别为简单工厂设计模式、工厂方法设计模式、抽象工厂设计模式;
简单工厂模式(Simple Factory):简单工厂模式又称为静态工厂方法模型,它属于类创建型模式。在简单工厂模式中,可以根据方法的参数不同返回不同类的实例。简单工厂专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
Tips:简单工厂设计模式不在GoF23种设计模式之中;
package com.dfbz.demo01_简单工厂设计模式.demo01_需求;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class Operation {
/**
* 计算方法
* @param num1
* @param num2
* @param operate
* @return
*/
public static Double getResult(double num1, double num2, String operate) {
Double result = 0.0D;
switch (operate) {
case "+":
result = num1 + num2;
break;
case "-":
result = num1 - num2;
break;
case "*":
result = num1 * num2;
break;
case "/":
result = num1 / num2;
break;
}
return result;
}
}
package com.dfbz.demo01_简单工厂设计模式.demo01_需求;
import java.util.Scanner;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class Demo01_测试加减乘除计算类 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入第一个数: ");
double num1 = scanner.nextDouble();
System.out.println("请输入第一个数: ");
double num2 = scanner.nextDouble();
System.out.println("请输入您要执行的运算符(+、-、*、/): ");
String operate = scanner.next();
Double result = Operation.getResult(num1, num2, operate);
System.out.println("运算的结果: " + result);
}
}
在上述案例程序中,代码耦合性太高,假设程序需要改进加法算法,则必须把所有的代码全部提供;并且由于所有的算法都在一起,试想一下假设一个加法算法的代码在几千行,那么程序将变得难以维护,不利于各个部件的单独升级,我们要做的是将各个部件独立出来;这样方便以后的升级扩展,并且各个模块相对独立;
package com.dfbz.demo01_简单工厂设计模式.demo02_使用接口改进;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public interface Operation {
/**
* 负责计算两个两个数的运算结果集,到底做什么运算,交给子类
* @param num1
* @param num2
* @return
*/
public Double getResult(Double num1,Double num2);
}
package com.dfbz.demo01_简单工厂设计模式.demo02_使用接口改进;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class OperationAdd implements Operation{
@Override
public Double getResult(Double num1, Double num2) {
return num1 + num2;
}
}
package com.dfbz.demo01_简单工厂设计模式.demo02_使用接口改进;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class OperationSub implements Operation {
@Override
public Double getResult(Double num1, Double num2) {
return num1 - num2;
}
}
package com.dfbz.demo01_简单工厂设计模式.demo02_使用接口改进;
import java.util.Scanner;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class Demo01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入第一个数: ");
double num1 = scanner.nextDouble();
System.out.println("请输入第一个数: ");
double num2 = scanner.nextDouble();
System.out.println("请输入您要执行的运算符(+、-、*、/): ");
String operate = scanner.next();
Operation operation = null;
switch (operate) {
case "+":
operation = new OperationAdd();
break;
case "-":
operation = new OperationSub();
}
Double result = operation.getResult(num1, num2);
System.out.println("计算的结果集为: " + result);
}
}
使用接口改进后的代码各个部件相对独立,如果以后需要修改加法类的算法也不用提供其他算法类的具体实现;但是上述代码中还存在一个具体的问题,那就是如果以后新增了其他的算法,源代码则需要一直改变;这样违反了开闭原则,我们的程序应该是"对扩展开放,对修改关闭";即类可以新增,但源代码尽量不要再修改;
package com.dfbz.demo01_简单工厂设计模式.demo03_使用简单工厂再改进;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class OperationFactory {
/**
* 根据计算方式来选择创建对应的对象
*
* @param method
* @return
*/
public static Operation createOperation(String method) {
Operation operation = null;
if (method.equals("+")) {
operation = new OperationAdd();
} else if (method.equals("-")) {
operation = new OperationSub();
}
return operation;
}
}
package com.dfbz.demo01_简单工厂设计模式.demo03_使用简单工厂再改进;
import java.util.Scanner;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class Demo01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入第一个数: ");
double num1 = scanner.nextDouble();
System.out.println("请输入第一个数: ");
double num2 = scanner.nextDouble();
System.out.println("请输入您要执行的运算符(+、-、*、/): ");
String method = scanner.next();
Operation operation = OperationFactory.createOperation(method);
Double result = operation.getResult(num1, num2);
System.out.println("计算的结果集为: " + result);
}
}
就这样,一个简单工厂设计模式就完成了。在简单工厂模式下,任何的运算逻辑新增或者修改,都不会影响客户端的代码(Demo01),只需要添加Operation的实现类,并且修改工厂类添加逻辑即可;降低了程序的耦合性;
但是,简单工厂只做到了一半的"开闭原则",因为在简单工厂中,新增了新的算法类,需要修改工厂类;如果我们需要频繁的新增一些算法则会导致频繁修改工厂类;简单工厂中,不仅对扩展开放了,对修改也开放了;
Tips:简单工厂只适合于产品对象较少,且产品固定的需求,对于产品变化无常的需求来说显然不合适;
工厂设计模式(Factory Method):指定一个创建对象的接口,由接口的实现类来决定实例化哪个类,工厂方法把类的实例化工作延迟到子类中进行;
在简单工厂中,随着产品链的丰富,则工厂的职责会变得越来越多,这样并不利于维护。工厂方法模式是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。
工厂方法中,不仅把产品抽象出来,连工厂类也抽象出来,具体生成什么产品由子类来决定;

在工厂方法中,如果要对算法进行扩展,那么就新增一个工厂并且再新增一个具体算法类即可,工厂方法完全符合了开闭原则的对扩展开发,对修改关闭的原则;
package com.dfbz.demo02_工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public interface IFactory {
Operation createOperation();
}
package com.dfbz.demo02_工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public interface Operation {
/**
* 负责计算两个两个数的运算结果集,到底做什么运算,交给子类
* @param num1
* @param num2
* @return
*/
public Double getResult(Double num1,Double num2);
}
package com.dfbz.demo02_工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class OperationAddFactory implements IFactory{
@Override
public Operation createOperation() {
return new OperationAdd();
}
}
package com.dfbz.demo02_工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class OperationSubFactory implements IFactory{
@Override
public Operation createOperation() {
return new OperationSub();
}
}
package com.dfbz.demo02_工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class OperationAdd implements Operation {
@Override
public Double getResult(Double num1, Double num2) {
return num1 + num2;
}
}
package com.dfbz.demo02_工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class OperationSub implements Operation {
@Override
public Double getResult(Double num1, Double num2) {
return num1 - num2;
}
}
package com.dfbz.demo02_工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class Demo01 {
public static void main(String[] args) {
// 创建工厂
IFactory factory=new OperationAddFactory();
// 创建运算类
Operation operation = factory.createOperation();
// 做运算
Double result = operation.getResult(20.0D, 30.0D);
}
}
工厂方法完完全全做到了开闭原则,以后我们要新增一些算法,或者第三方厂商想要新增一些算法,那么直接进行子类扩展就行;
在工厂方法设计模式中,工厂生产的是总是同一类的产品;例如产品1工厂只能生产产品1,产品2工厂只能生产产品2;这些工厂只生产同种类产品,而抽象工厂模式将考虑多种类产品的生产。在抽象工厂中,将同一种工厂生产出来的产品称为同族产品,而同一种工厂生产出来的不同产品称为同级产品;
例如电子设备工厂能够生产手机,笔记本;旗下有小米工厂,华为工厂;小米工厂能够生产小米手机,小米笔记本;华为工厂能够生产华为手机,华为笔记本;
程序类图如下:


同族:只要是同一个工厂生产的产品都属于同族产品;

同级:工厂生产出来的产品的类别称为级别,所属同一个类别的产品,那么就是同级别产品;

同族是有相对概念的问题,主要看我们的程序是如何设计的
关于同族:只要是同一个工厂生产的产品都属于同族产品;
关于同级:工厂生产出来的产品的类别称为级别,所属同一个类别的产品,那么就是同级别产品;
例如,在下面类图中,同族与同级的关系发生了变化:


同族产品:

同级产品:

抽象工厂模式的主要角色如下。
基于类图设计程序:

抽象工厂:
package com.dfbz.demo03_抽象工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro: 电子设备工厂, 用于生产电子设备
*/
public abstract class AbstractFactory {
// 生产手机
public abstract Phone createPhone();
// 生产笔记本
public abstract Laptop createLaptop();
}
package com.dfbz.demo03_抽象工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro: 小米工厂,用于生产小米的设备
*/
public class XiaoMiFactory extends AbstractFactory{
@Override
public Phone createPhone() {
return new XiaoMiPhone();
}
@Override
public Laptop createLaptop() {
return new XiaoMiLaptop();
}
}
package com.dfbz.demo03_抽象工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro: 华为工厂,用于生产华为的设备
*/
public class HuaWeiFactory extends AbstractFactory {
@Override
public Phone createPhone() {
return new HuaWeiPhone();
}
@Override
public Laptop createLaptop() {
return new HuaWeiLaptop();
}
}
package com.dfbz.demo03_抽象工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro: 抽象产品,抽象手机,每个手机的功能是不一样的,具体的实现交给子类
*/
public abstract class Phone {
public abstract void sendMsg();
}
package com.dfbz.demo03_抽象工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro: 抽象产品,抽象笔记本,每个笔记本的功能是不一样的,具体的实现交给子类
*/
public abstract class Laptop {
public abstract void play();
}
package com.dfbz.demo03_抽象工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class XiaoMiPhone extends Phone {
@Override
public void sendMsg() {
System.out.println("使用小米手机发送短信....");
}
}
package com.dfbz.demo03_抽象工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class XiaoMiLaptop extends Laptop {
@Override
public void play() {
System.out.println("使用小米笔记本打游戏...");
}
}
package com.dfbz.demo03_抽象工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class HuaWeiPhone extends Phone {
@Override
public void sendMsg() {
System.out.println("使用华为手机发送短信....");
}
}
package com.dfbz.demo03_抽象工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class HuaWeiLaptop extends Laptop {
@Override
public void play() {
System.out.println("使用华为笔记本打游戏...");
}
}
package com.dfbz.demo03_抽象工厂设计模式;
/**
* @author lscl
* @version 1.0
* @intro:
*/
public class Demo01 {
public static void main(String[] args) {
// 使用华为工厂来创建电子设备
AbstractFactory factory=new HuaWeiFactory();
Laptop laptop = factory.createLaptop();
Phone phone = factory.createPhone();
laptop.play();
phone.sendMsg();
System.out.println("----------");
// 使用小米工厂来创建电子设备
AbstractFactory factory2=new XiaoMiFactory();
Laptop laptop2 = factory.createLaptop();
Phone phone2 = factory.createPhone();
laptop2.play();
phone2.sendMsg();
}
}
优点:
缺点: