工厂模式
概述
工厂模式是指 在父类中定义创建对象的一个接口,由子类来决定实例化哪个类。
工厂模式分为:简单工厂模式,工厂方法模式,抽象工厂模式。
简单工厂模式
简单工厂模式是工厂模式的一种实现,它主要分为:
- 分配任务的工厂角色;
- 大致描述所有功能的抽象产品角色
- 实现某一具体功能的具体产品角色
由于它每次新添加一个产品,都需要多生成if-else语句(或switch-case语句),这违背了开放-封闭原则。因此该模式使用得较少。
开放-封闭原则:强调设计的模块应该从不改变,当需求变化时(添加产品),通过添加新代码来扩展这个模块的行为,但不会去修改已存在且可工作的代码。
举例说明:我们要定义多种绘制不同形状的绘图工具。
先定义一个工具接口:
public interface Shape {
void draw();
}
然后创建各个不同的工具:
public class Circle implements Shape {
public Circle() {
System.out.println("Circle");
}
@Override
public void draw() {
System.out.println("Draw Circle");
}
}
public class Rectangle implements Shape {
public Rectangle() {
System.out.println("Rectangle");
}
@Override
public void draw() {
System.out.println("Draw Rectangle");
}
}
public class Square implements Shape {
public Square() {
System.out.println("Square");
}
@Override
public void draw() {
System.out.println("Draw Square");
}
}
接着创建工厂类:
public class ShapeFactory {
// getShape方法用于根据参数shapeType来返回不同的绘图工具
public static Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
} else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
return new Rectangle();
} else if (shapeType.equalsIgnoreCase("SQUARE")) {
return new Square();
}
return null;
}
}
最后测试一下:
public class Test {
public static void main(String[] args) {
Shape circle = ShapeFactory.getShape("CIRCLE");
circle.draw();
Shape rectangle = ShapeFactory.getShape("RECTANGLE");
rectangle.draw();
}
}
不过该实现有一个小问题:若要增加新绘图工具,就需要修改工厂类的方法。
反射机制改善简单工厂
我们可以通过反射来修改下工厂类的getShape()方法:
public class ShapeFactory {
public static Object getClass(Class<? extends Shape> clazz) {
Object obj = null;
try {
obj = Class.forName(clazz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
}
最后测试一下:
public class Test {
public static void main(String[] args) {
Circle circle = (Circle) ShapeFactory.getClass(Ano.Circle.class);
circle.draw();
Rectangle rectangle = (Rectangle) ShapeFactory.getClass(Ano.Rectangle.class);
rectangle.draw();
}
}
工厂方法模式
在该模式下每个产品都有对应的工厂。其主要角色有:
- 抽象工厂角色
- 具体工厂角色
- 抽象产品角色
- 具体产品角色
同样以绘图工具为例,在上面的基础上:首先增加一个工厂接口
public interface Factory {
public Shape getShape();
}
增加相关工具的具体工厂类:
public class CircleFactory implements Factory {
@Override
public Shape getShape() {
return new Circle();
}
}
public class RectangleFactory implements Factory{
@Override
public Shape getShape() {
return new Rectangle();
}
}
public class SquareFactory implements Factory{
@Override
public Shape getShape() {
return new Square();
}
}
最后测试:
public class Test {
public static void main(String[] args) {
Factory circlefactory = new CircleFactory();
Shape circle = circlefactory.getShape();
circle.draw();
}
}
工厂方法模式适用于如下场景:
(1)一个类对象不知道对应的类:我们不需要知道具体的产品类(本例中的Circle类 ),只需知道生产该产品的工厂类(本例中的CircleFactory类)即可,具体的产品由工厂负责。如本例中我们只需知道工厂接口及其绘图工厂实现类。
(2)一个类通过其子类来指定创建指定对象:抽象工厂接口只需提供创建产品的接口,然后由工厂子类来确定要创建的对象。如本例中的工厂接口通过其圆形绘图工具实现类来实现功能。
抽象工厂模式
在工厂模式中,一个工厂类仅生成一种产品。而在抽象工厂模式下,一个工厂类可以创建多组产品,一个工厂类中的多组产品通常是有关联的。
该模式下的产品角色有:
- 抽象工厂角色
- 具体工厂角色
- 抽象产品角色
- 具体产品角色
以枪械AK47,M4A1为例,两把枪使用的子弹类型分别为AK_Bullet,M4_Bullet。工厂类可分为生成枪械和对应子弹的两种工厂。
定义枪械,子弹的工厂接口:
public interface Gun {
public void shooting();
}
public interface Bullet {
public void load();
}
创建对应的枪,子弹具体产品类
public class AK implements Gun{
@Override
public void shooting() {
System.out.println("shooting with AK");
}
}
public class M4A1 implements Gun {
@Override
public void shooting() {
System.out.println("shooting with M4A1");
}
}
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("bullets with AK");
}
}
public class M4A1_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with M4A1");
}
}
创建生成枪械,子弹的具体工厂类
public class AK_Factory implements Factory{
@Override
public Gun produceGun() {
return new AK();
}
@Override
public Bullet produceBullet() {
return new AK_Bullet();
}
}
public class M4A1_Factory implements Factory{
@Override
public Gun produceGun() {
return new M4A1();
}
@Override
public Bullet produceBullet() {
return new M4A1_Bullet();
}
}
该模式的适用场景:
(1)与工厂模式一样,不知道产品类对象对应的产品类
(2)需要多个产品完成某种功能,并且可能存在多个产品完成不同功能的情况。比如本例中一把枪的发射功能是由枪械类对象的发射方法shooting()和它所属的子弹类对象的爆炸方法load()两部分组成。
(3)系统结构稳定,不会频繁增加对象。(一旦增加就需要修改原代码,这会破坏开闭原则)。