自大学课程初识设计模式以来,就越发觉得有必要系统学习一下设计模式。
刚好在实习前准备期间课比较少,抽出一点时间整理一下记一些笔记,复制粘贴比较多。
笔记比较适合学习过设计模式的同学。
Simple Factory Pattern(简单工厂模式)
学习链接:极客学院Wiki_Java设计模式之创造型模式
简单工厂模式的适用范围
(1) 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
反映到代码上就是Factory类逻辑要简单就要创建对象少
(2) 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
顾客不应该知道产品是如何做的,只需要知道自己需要的产品的名字。
简单工厂模式如何实现
角色
Factory(工厂角色)
工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法 factoryMethod(),它的返回类型为抽象产品类型 Product。
Product(抽象产品角色)
它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
ConcreteProduct(具体产品角色)
它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。
类图
可以看到类图中除了上述,在Factory类中还有一个方法用于根据客户端参数返回产品对象,因此客户端只需要提供参数而不使用new XXX来创造产品。
当然Factory类有时也可以与Product类结合成一个类
简单工厂模式的优缺点
主要优点
(1) 工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离。
(2) 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。
(3) 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
主要缺点
(1) 由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响。
(2) 使用简单工厂模式势必会增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度。
(3) 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
(4) 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。(这一点其实我不是很懂,有懂的朋友教我一下吗?)
练习
题目
使用简单工厂模式设计一个可以创建不同几何形状(如圆形、方形和三角形等)的绘图工具,每个几何图形都具有绘制 draw() 和擦除 erase() 两个方法,要求在绘制不支持的几何图形时,提示一个 UnSupportedShapeException。
实现代码
抽象产品:Shape.java
package com.joy;
public abstract class Shape {
public abstract void draw();
public abstract void erase();
}
具体产品:Circle.java
package com.joy;
public class Circle extends Shape{
@Override
public void draw() {
System.out.println("绘制圆形");
}
@Override
public void erase() {
System.out.println("擦除圆形");
}
}
具体产品:Rectangle.java
package com.joy;
public class Rectangle extends Shape{
@Override
public void draw() {
System.out.println("绘制长方形");
}
@Override
public void erase() {
System.out.println("擦除长方形");
}
}
具体产品:Triangle.java
package com.joy;
public class Triangle extends Shape{
@Override
public void draw() {
System.out.println("绘制三角形");
}
@Override
public void erase() {
System.out.println("擦除三角形");
}
}
工厂类:Factory.java
这个地方有一点不好,为了图方便把UnSupportedShapeException类写在这个方法里了,应该独立分开的。
package com.joy;
public class Factory {
public static Shape getShape(String shapeName) throws UnSupportedShapeException{
if(shapeName.equals("Circle"))
return new Circle();
else if(shapeName.equals("Rectangle"))
return new Rectangle();
else if(shapeName.equals("Triangle"))
return new Triangle();
else
throw new UnSupportedShapeException();
}
}
class UnSupportedShapeException extends Exception{
}
客户端:SimpleFactoryDemo.java
package com.joy;
public class SimpleFactoryDemo {
public static void main(String[] args) {
Factory f = new Factory();
try {
System.out.println("*获取指定形状");
Shape shape = f.getShape("Circle");//圆形
System.out.println("*控制绘制");
shape.draw();
System.out.println("*控制擦除");
shape.erase();
System.out.println("*获取指定形状");
Shape shape1 = f.getShape("Square");//正方形,没有该形状
} catch (UnSupportedShapeException e) {
e.printStackTrace();
}
}
}
运行结果
总结
简单工厂虽然把产品都独立出来,将创建和调用分开了,但是Factory方法变得复杂和不灵活,应该改进。