工厂模式详解

一般情况下,工厂模式分为三种更加细分的类型:简单工厂、工厂方法和抽象工厂。不过,在 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就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度

其次,工厂模式是一种典型的解耦模式,迪米特法则(最少知道原则,一个类对于其他类知道的越少越好)在工厂模式中表现的尤为明显。假如调用者自己组装产品需要减少依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。

再次,由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好。也就是说,当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。

上一篇:Partial shape-preserving splines


下一篇:python实现图片对比五种算法