简单工厂模式并不属于 GoF 23 个经典设计模式,但通常用它作为学习其它工厂模式的基础。
简单工厂模式定义
定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态方法,所以简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。
当需要某种类实例的时候只需要传入一个正确的参数,就可以获取你想要的对象,而无需知道其创建细节。简单工厂模式的核心是工厂类的设计。
简单工厂模式结构
1、Factory(工厂角色):工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。在工厂类中提供了静态的工厂方法,它的返回类型为抽象产品类型。
2、Product(抽象产品角色):它是工厂类所创建的所有对象的父类,封装了各种产品对象的共有方法。
3、ConcreteProduct(具体产品角色):它是简单工厂模式的目标,所有被创建的对象都是这个角色的某个类的实例。每个具体产品角色都继承了抽象产品角色,需要实现抽象产品中声明的抽象方法。
简单工厂模式示例
设计简单工厂模式的步骤如下:
第一步:声明抽象产品角色,可以为抽象类,可以为接口
/**
* Author: YiFan
* Date: 2018/12/7 12:38
* Description: 抽象产品角色-汽车类
*/
public abstract class Car {
// 抽象方法-描述汽车品牌
public abstract void desc();
}
第二步:声明具体产品角色,继承抽象产品角色,实现父类中的抽象方法
/**
* Author: YiFan
* Date: 2018/12/7 12:38
* Description: 具体产品角色-宝马汽车类
*/
public class BMWCar extends Car {
@Override
public void desc() {
System.out.println("宝马汽车");
}
}
/**
* Author: YiFan
* Date: 2018/12/7 12:39
* Description: 具体产品角色-奥迪汽车类
*/
public class AuDiCar extends Car {
@Override
public void desc() {
System.out.println("奥迪汽车");
}
}
第三步:声明工厂角色,SimpleCarFactory 为工厂类,提供一个静态工厂方法供外界调用,根据传入的参数创建不同的产品对象
/**
* Author: YiFan
* Date: 2018/12/7 12:40
* Description: 工厂类
*/
public class SimpleCarFactory {
/**
* 静态方法-根据传入的参数返回不同类实例
* @param type 传入的汽车品牌
* @return Car对象实例
*/
public static Car createCar(String type) {
// 如果传入的是"BMW",则返回BMWCar类实例
if ("BMW".equals(type)) {
return new BMWCar();
// 如果传入的是"AuDi",则返回AuDiCar类实例
} else if ("AuDi".equals(type)) {
return new AuDiCar();
} else {
System.out.println("无法识别的类型");
return null;
}
}
}
第四步:设计客户端,通过调用工厂类中的静态工厂方法获取相应的产品对象
/**
* Author: YiFan
* Date: 2018/12/7 12:41
* Description: 客户端
*/
public class Client {
public static void main(String[] args) {
Car car;
car = SimpleCarFactory.createCar("BMW");
car.desc();
}
}
执行结果:
宝马汽车
四个步骤:抽象产品角色->具体产品角色->工厂角色->客户端
简单工厂模式简化
有时候,为了简化简单工厂模式,可以将抽象产品角色和工厂角色结合,将静态工厂方法移至抽象产品角色中。在以上示例中,SimpleCarFactory 工厂角色与 Car 抽象产品角色结合,代码如下:
public abstract class Car {
// 抽象方法-所有子类的共同方法
public abstract void desc();
// 静态工厂方法
public static Car createCar(String type) {
if ("BMW".equals(type)) {
return new BMWCar();
} else if ("AuDi".equals(type)) {
return new AuDiCar();
} else {
System.out.println("无法识别的类型");
return null;
}
}
}
简单工厂模式总结
简单工厂模式提供了专门的工厂类用于创建对象,将对象的创建和对象的使用分离开,它作为一种最简单的工厂模式在软件开发中得到了较为广泛的应用。
主要优点
1、工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离。
2、客户的那无需知道所创建的具体产品类的类名,只需知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。
主要缺点
1、由于工厂类集中了所有产品的创建逻辑,职责过重,一旦无法正常工作则会导致整个系统受到影响。
2、使用简单工厂模式势必会增加系统中类的个数(引入新的工厂类),增加了系统的复杂度和理解难度。
3、系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,如果产品类型很多,则会导致工厂类逻辑过于复杂,不利于系统的扩展和维护。
适用场景
1、工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过于复杂。
2、客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
简单工厂模式练习
使用简单工厂模式设计一个可以创建不同几何形状(如圆形、方形和三角形等)的绘图工具,每个几何图形都具有绘制 draw() 和擦除 erase() 两个方法,要求在绘制不支持的几何图形时,提示一个 UnSupportedShapeException。
设计结构图如下:
设计思路如下:
第一步:声明抽象产品角色
/**
* Author: YiFan
* Date: 2018/12/10 19:22
* Description: 抽象产品角色
*/
public abstract class Shape {
public abstract void draw();
public abstract void erase();
}
第二步:声明具体产品角色
/**
* Author: YiFan
* Date: 2018/12/10 19:23
* Description: 具体产品角色
*/
public class Round extends Shape {
@Override
public void draw() {
System.out.println("绘制圆形");
}
@Override
public void erase() {
System.out.println("擦除圆形");
}
}
/**
* Author: YiFan
* Date: 2018/12/10 19:25
* Description: 具体产品角色
*/
public class Square extends Shape {
@Override
public void draw() {
System.out.println("绘制方形");
}
@Override
public void erase() {
System.out.println("擦除方形");
}
}
/**
* Author: YiFan
* Date: 2018/12/10 19:26
* Description: 具体产品角色
*/
public class Triangle extends Shape {
@Override
public void draw() {
System.out.println("绘制三角形");
}
@Override
public void erase() {
System.out.println("擦除三角形");
}
}
第三步:声明工厂角色
/**
* Author: YiFan
* Date: 2018/12/10 19:27
* Description: 工厂角色
*/
public class ShapeFactory {
// 声明创建形状的静态工厂方法
public static Shape createShape(String type)
throws UnSupportedShapeException {
Shape shape;
if ("圆形".equals(type)) {
shape = new Round();
} else if ("方形".equals(type)) {
shape = new Square();
} else if ("三角形".equals(type)) {
shape = new Triangle();
} else {
throw new UnSupportedShapeException("UnSupportedShapeException");
}
return shape;
}
}
/**
* Author: YiFan
* Date: 2018/12/10 19:43
* Description: 自定义异常
*/
public class UnSupportedShapeException extends Exception {
public UnSupportedShapeException(String message) {
super(message);
}
}
第四步:设计客户端
/**
* Author: YiFan
* Date: 2018/12/10 19:34
* Description: 客户端
*/
public class DrawingTool {
public static void main(String[] args) {
Shape s1, s2, s3, s4;
try {
s1 = ShapeFactory.createShape("圆形");
s2 = ShapeFactory.createShape("方形");
s3 = ShapeFactory.createShape("三角形");
// s4 = ShapeFactory.createShape("六边形");
s1.draw();
s1.erase();
s2.draw();
s2.erase();
s3.draw();
s3.erase();
// s4.draw();
// s4.erase();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
执行结果为:
绘制圆形
擦除圆形
绘制方形
擦除方形
绘制三角形
擦除三角形
去掉其中的三处注释后,执行结果为:
UnSupportedShapeException