一、概述
工厂模式是创建型设计模式,它提供了一种创建对象的最佳方式。在工厂模式中,创建对象不会对客户端暴露创建逻辑,隐藏创建对象的详情,从而实现客户端与具体实现的解耦。工厂模式设计时需求注意的点:
- 工厂类提供公共的方法来创建对象,无论静态,而不是客户端直接创建
- 方法的参数可选,但参数只用来决定哪种实现,不应该存在业务参数
- 方法的返回一般是被创建的接口对象,也可以是抽象类或具体类
常见的工厂模式有工厂方法模式、简单工厂模式和抽象工厂模式等,并不要拘泥于哪种,在实际业务中根据需求设计。
二、工厂方法
工厂方法模式(Factory Method)定义一个用于创建对象的接口,让子类决定实例化哪一个类,使一个类的实例化延迟到其子类。在代码中,使用不同的工厂子类创建不同的对象,创建对象的细节封装在子类中。比如我们使用工厂方法来实现绘制不同形状的图形。
定义一个 Shape
接口,并添加实现类,编写示例代码如下:
// Shape.java public interface Shape { void draw(); } // Circle.java public class Circle implements Shape { @Override public void draw() { System.out.println("Circle.draw"); } } // Rectangle.java public class Rectangle implements Shape { @Override public void draw() { System.out.println("Rectangle.draw"); } } // Square.java public class Square implements Shape { @Override public void draw() { System.out.println("Square.draw"); } }
针对 Shape
接口定义一个抽象工厂类 ShapeFactory
,并添加各个实例类的工厂子类,编写代码如下:
// ShapeFactory.java public abstract class ShapeFactory { public void operate() { Shape shape = factoryMethod(); shape.draw(); } // 将创建对象的细节交给子类 protected abstract Shape factoryMethod(); } // CircleFactory.java public class CircleFactory extends ShapeFactory { @Override protected Shape factoryMethod() { return new Circle(); } } // RectangleFactory.java public class RectangleFactory extends ShapeFactory { @Override protected Shape factoryMethod() { return new Rectangle(); } } // SquareFactory.java public class SquareFactory extends ShapeFactory { @Override protected Shape factoryMethod() { return new Square(); } }
编写主方法类,运行示例代码:
// Main.java public class Main { public static void main(String[] args) { new CircleFactory().operate(); new RectangleFactory().operate(); new SquareFactory().operate(); } }
三、简单工厂
简单工厂模式(Factory)定义用于创建对象的类,客户端调用工厂类方法(静态或非静态)根据参数类型创建不同的对象实例,从而使得客户端和实现之间解耦。比如我们使用简单静态工厂来绘制不同形状的图形。
定义一个工厂类,添加静态方法来根据类型创建不同实例,编写代码如下:
public class ShapeFactory { public static Shape getShape(String shapeType) { if ("CIRCLE".equalsIgnoreCase(shapeType)) { return new Circle(); } if ("RECTANGLE".equalsIgnoreCase(shapeType)) { return new Rectangle(); } if ("SQUARE".equalsIgnoreCase(shapeType)) { return new Square(); } return null; } }
编写主方法类,运行示例代码:
public class Main { public static void main(String[] args) { Shape circle = ShapeFactory.getShape("CIRCLE"); circle.draw(); Shape rectangle = ShapeFactory.getShape("RECTANGLE"); rectangle.draw(); Shape square = ShapeFactory.getShape("SQUARE"); square.draw(); } }
简单工厂与工厂方法不一样的地方是简单工厂是客户端根据方法的参数类型来创建不同的对象。参数类型可以是整型数据、字符串等基本数据类型,也可以是枚举或其他类型,只要可以区分创建对象的实例类型就行,我们也可以利用环境配置,或者某个 Profile 来确定创建的对象实例,以达到兼容的目的。
四、抽象工厂
抽象工厂模式(Abstract Factory)和工厂模式很相似,抽象工厂对工厂类进行了一层抽象,抽象的工厂类(超级工厂)可以创建其他工厂。比如我们基于前面的例子绘制不同形状的图形,并且给图形填充不同的颜色
定义一个 Color
颜色接口,并添加实现类,编写示例代码如下:
// Color.java public interface Color { void fill(); } // Red.java public class Red implements Color { @Override public void fill() { System.out.println("Red.fill"); } } // Green.java public class Green implements Color { @Override public void fill() { System.out.println("Green.fill"); } } // Blue.java public class Blue implements Color { @Override public void fill() { System.out.println("Blue.fill"); } }
定义一个抽象工厂,并添加形状和颜色的实现工厂类,编写代码如下:
// AbstractFactory.java public abstract class AbstractFactory { public abstract Color getColor(String color); public abstract Shape getShape(String shape); } // ShapeFactory.java public class ShapeFactory extends AbstractFactory { @Override public Shape getShape(String shape) { if ("CIRCLE".equalsIgnoreCase(shape)) { return new Circle(); } else if ("RECTANGLE".equalsIgnoreCase(shape)) { return new Rectangle(); } else if ("SQUARE".equalsIgnoreCase(shape)) { return new Square(); } return null; } @Override public Color getColor(String color) { return null; } } // ColorFactory.java public class ColorFactory extends AbstractFactory { @Override public Color getColor(String color) { if ("RED".equalsIgnoreCase(color)) { return new Red(); } else if ("GREEN".equalsIgnoreCase(color)) { return new Green(); } else if ("BLUE".equalsIgnoreCase(color)) { return new Blue(); } return null; } @Override public Shape getShape(String shape) { return null; } }
定义超级工厂类,用于生产工厂类,编写代码如下:
// FactoryProducer.java public class FactoryProducer { public static AbstractFactory getFactory(String choice) { if ("SHAPE".equalsIgnoreCase(choice)) { return new ShapeFactory(); } else if ("COLOR".equalsIgnoreCase(choice)) { return new ColorFactory(); } return null; } }
编写主方法类,运行示例代码
// Main.java public class Main { public static void main(String[] args) { AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE"); Shape shape; shape = shapeFactory.getShape("CIRCLE"); shape.draw(); shape = shapeFactory.getShape("RECTANGLE"); shape.draw(); shape = shapeFactory.getShape("SQUARE"); shape.draw(); AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR"); Color color; color = colorFactory.getColor("RED"); color.fill(); color = colorFactory.getColor("GREEN"); color.fill(); color = colorFactory.getColor("BLUE"); color.fill(); } }
抽象工厂模式基于简单工厂模式又对工厂进行了一层抽象,将工厂类也以工厂的形式创建。
五、Spring实现工厂
Spring容器管理一个接口的多个实现类Bean时,可以使用 Map
形式注入所有实现类的Bean,这个Map的Key为注册Bean的BeanName,Map的Value为对应的Bean。所以我们可以利用这个特性使用Spring的IoC功能实现一个工厂模式,还是使用前面的示例。
Spring 默认注册的 BeanName 一般为类名的小驼峰形式,也可以自己指定。
定义一个 Shape
接口,并添加实现类,此时所有的实现类交给Spring管理,编写代码如下:
// Shape.java public interface Shape { void draw(); } // Circle.java @Service public class Circle implements Shape { @Override public void draw() { System.out.println("Circle.draw"); } } // Rectangle.java @Service public class Rectangle implements Shape { @Override public void draw() { System.out.println("Rectangle.draw"); } } // Square.java @Service public class Square implements Shape { @Override public void draw() { System.out.println("Square.draw"); } }
定义一个工厂类,也要交给Spring管理,然后使用 Map
注入需要生产的Bean,编写代码如下:
// ShapeFactory.java @Service public class ShapeFactory { private static Map<String, Shape> shapeMap; public static Shape getShape(String beanName) { return shapeMap.get(beanName); } @Autowired public void setShapeMap(Map<String, Shape> shapeMap) { ShapeFactory.shapeMap = shapeMap; } }
编写主方法类,定义ApplicationContext并扫描前面注册Bean所在的包,编写代码如下:
// Main.java public class Main { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext("com.ajn.spring.factory"); Shape circle = ShapeFactory.getShape("circle"); circle.draw(); Shape rectangle = ShapeFactory.getShape("rectangle"); rectangle.draw(); Shape square = ShapeFactory.getShape("square"); square.draw(); } }