一般情况下,工厂模式分为三种更加细分的类型:简单工厂、工厂方法和抽象工厂。不过,在 GoF 的《设计模式》一书中,它将简单工厂模式看作是工厂方法模式的一种特例,所以工厂模式只被分成了工厂方法和抽象工厂两类。而在菜鸟教程中,又将简单工厂模式直接叫做工厂模式,分成了工厂模式(简单工厂模式)和抽象工厂模式两类,这里就少讲了工厂方法模式。
其实这些分类没那么重要,我们直接把这细分的三种类型都弄懂了就行了。
简单工厂模式
简单工厂模式是 Java 中最常用的设计模式之一,属于创建型模式,在工厂方法模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
简单工厂模式UML图:
从这图可以看出简单工厂模式的实现还是比较简单的,直接上代码:
//这是一个创建对象(实现的)的接口
public interface Shape {
void draw();
}
//下面是两个实现接口的实体类
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
//这就是一个工厂类,,生成基于给定信息的实体类的对象。
public class ShapeFactory {
//使用 getShape 方法获取形状类型的对象
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
//测试类,通过使用该工厂,传递类型信息来获取实体类的对象。
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
//获取 Rectangle 的对象,并调用它的 draw 方法
Shape shape1 = shapeFactory.getShape("RECTANGLE");
//调用 Rectangle 的 draw 方法
shape1.draw();
//获取 Square 的对象,并调用它的 draw 方法
Shape shape = shapeFactory.getShape("SQUARE");
//调用 Square 的 draw 方法
shape2.draw();
}
}
简单工厂模式实现了生成产品类的代码跟客户端(测试)代码分离,在工厂类中你可以添加所需的生成产品的逻辑代码,但是问题来了,优秀的java代码是符合“开放-封闭”原则的,也就是说对扩展开发,对修改关闭,如果你要加一个产品类3,你就要修改工厂类里面的生成产品的代码,在这里你就要增加if-else判断。对于这个问题,我们的工厂方法模式就可以解决这个问题。
工厂方法模式
产品类中增加了Circle
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
//与简单工厂模式不同,在这里先声明工厂接口
public interface Factory {
//声明产生产品类的方法
public Product getShape();
}
//生产Rectangle的RectangleFactory
public class RectangleFactory implements Factory {
//实现工厂类的方法生产 Rectangle
public Shape getShape(){
return new Rectangle();
}
}
//生产Square 的SquareFactory
public class SquareFactory implements Factory {
//实现工厂类的方法生产 Square
public Shape getShape(){
return new Square();
}
}
//生产Circle 的CircleFactory
public class CircleFactory implements Factory {
//实现工厂类的方法生产 Circle
public Shape getShape(){
return new Circle ();
}
}
//测试类,通过使用各自的工厂,来获取实体类的对象。
public class FactoryPatternDemo {
public static void main(String[] args) {
Factory factory;
//获取 Rectangle 的对象
factory = new RectangleFactory();
Shape shape1 = factory .getShape();
//获取 Square 的对象
factory = new SquareFactory();
Shape shape2 = factory .getShape();
//获取 Circle的对象
factory = new CircleFactory();
Shape shape3 = factory .getShape();
}
}
工厂方法模式的UML图:(举了一个别的例子)
工厂方法模式中我们把生成产品类的时间延迟,就是通过对应的工厂类来生成对应的产品类,在这里我们就可以实现“开发-封闭”原则,无论加多少产品类,我们都不用修改原来类中的代码,而是通过增加工厂类来实现。但是这还是有缺点的,如果产品类过多,我们就要生成很多的工厂类。假如我们要实现的产品接口不止一个,也就是有多个产品接口,不同产品接口有对应的产品族。什么是产品族呢?简单的理解就是,不同牌子产的车里面会有跑车类型,家庭类型,商用类型等的车,不同牌子的车的跑车类型的车可以组成一个产品族。对于这种情况我们可以采用抽象工厂模式。
简单工厂模式跟工厂方法模式的区别:
简单工厂模式跟工厂方法模式极为相似。
区别是:简单工厂只有三个要素(实体类接口,实体类,工厂类),他没有工厂接口,并且得到产品的方法一般是静态的。因为没有工厂接口,所以在工厂实现的扩展性方面稍弱,可以算所工厂方法模式的简化版。
抽象工厂模式
抽象工厂模式是围绕一个超级工厂创建其他工厂。该超级工厂又可以理解为其他工厂的工厂。
抽象工厂模式的UML图:
抽象工厂模式我觉得可以理解为简单工厂模式的嵌套,简单工厂模式里面还有一个简单工厂模式。工厂是实体类的生成器,而工厂又有一个工厂生成器。
//形状的接口
public interface Shape {
void draw();
}
//颜色的接口
public interface Color {
void fill();
}
//这里实现这两个接口的实体类就省略了
//工厂的抽象类,用来获取工厂。
public abstract class AbstractFactory {
public abstract Color getColor(String color);
public abstract Shape getShape(String shape) ;
}
//扩展了 AbstractFactory 的工厂类,用来创建形状实体类的工厂
public class ShapeFactory extends AbstractFactory {
@Override
public 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;
}
@Override
public Color getColor(String color) {
return null;
}
}
//扩展了 AbstractFactory 的工厂类,用来创建颜色实体类的工厂
public class ColorFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
return null;
}
@Override
public Color getColor(String color) {
if(color == null){
return null;
}
if(color.equalsIgnoreCase("RED")){
return new Red();
} else if(color.equalsIgnoreCase("GREEN")){
return new Green();
} else if(color.equalsIgnoreCase("BLUE")){
return new Blue();
}
return null;
}
}
创建一个工厂生成器类,通过传递形状或颜色信息来获取工厂。
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
} else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}
//测试类,使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。
public class AbstractFactoryPatternDemo {
public static void main(String[] args) {
//获取形状工厂
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
//获取形状为 Circle 的对象
Shape shape1 = shapeFactory.getShape("CIRCLE");
//调用 Circle 的 draw 方法
shape1.draw();
//获取形状为 Rectangle 的对象
Shape shape2 = shapeFactory.getShape("RECTANGLE");
//调用 Rectangle 的 draw 方法
shape2.draw();
//获取颜色工厂
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
//获取颜色为 Red 的对象
Color color1 = colorFactory.getColor("RED");
//调用 Red 的 fill 方法
color1.fill();
//获取颜色为 Green 的对象
Color color2 = colorFactory.getColor("Green");
//调用 Green 的 fill 方法
color2.fill();
}
}
抽象工厂模式中我们可以定义实现不止一个接口,一个工厂也可以生成不止一个产品类,抽象工厂模式较好的实现了“开放-封闭”原则,是三个模式中较为抽象,并具一般性的模式。我们在使用中要注意使用抽象工厂模式的条件。
简单工厂和工厂方法比较常用,抽象工厂的应用场景比较特殊,所以很少用到。
工厂模式的适用场景:
不管是简单工厂模式,工厂方法模式还是抽象工厂模式,他们具有类似的特性,所以他们的适用场景也是类似的。
首先,作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
其次,工厂模式是一种典型的解耦模式,迪米特法则(最少知道原则,一个类对于其他类知道的越少越好)在工厂模式中表现的尤为明显。假如调用者自己组装产品需要减少依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。
再次,由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好。也就是说,当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。