Spring IOC中使用的设计模式(二) 工厂模式

Spring IOC中使用的设计模式(二) 工厂模式

问题引入

问题:现在有一家工厂,生产电视和空调等,平常的做法是,创建一个生产电视和一个生产空调的类。

public class ProductTv {
    ProductTv(){
        System.out.println("生产电视");
    }
}
/**
 * Created on 2018/5/27
 *
 * @author wang.teng
 */
public class ProductRefrigerator {
    ProductRefrigerator(){
        System.out.println("生产冰箱");
    }
}

在我们使用的时候:

/**
 * Created on 2018/5/27
 *
 * @author wang.teng
 */
public class Test {
    public static void main(String[] args) {
        //生产电视
        ProductTv productTv = new ProductTv();
        //生产冰箱
        ProductRefrigerator productRefrigerator = new ProductRefrigerator();
    }
}

大家会发现这么说耦合性太高,工厂和电器紧密的耦合在一起了。那么如何分离使用者和对象的分离呢?

一、 什么是工厂模式

专门负责将大量有共同接口的类的实例化。工厂模式可以动态的决定将哪个类进行实例化。

二、为什么要使用工厂模式

让使用者和对象的创建分离。减少修改,拓展比较好。

三、工厂模式的几种形态

  1. 简单工厂模式

    • 角色

      • 工厂类角色:核心,与应用逻辑紧密相关。直接调用创建产品对象
      • 抽象产品:往往是一个接口或者抽象类,
      • 具体产品:所有角色的实例控制类。
    • 举例说明

      根据上面的例子进行改造,讲生产作为一个接口抽象出来一个产品

      1. 产品接口:
    public interface Product {
    }
    1. 产品实现

      public class Tv implements Product {
        public Tv(){
            System.out.println("电视被制造了");
        }
      }
      public class Refrigerator implements Product {
        public Refrigerator(){
            System.out.println("冰箱被制造了");
        }
      }
    2. 工厂类:

      • 判断传入的key
      public class ProductFactory {
          public static Product produce(String productName) throws Exception {
              switch (productName) {
                  case "tv":
                      return new Tv();
                  case "refrigerator":
                      return new Refrigerator();
                  default:
                      throw new Exception("没有该产品");
              }
          }
      }
      • 配置文件模式

        新增配置文件:

      tv=design.pattern.Tv
      refrigerator=design.pattern.Refrigerator

      读取配置到map中:

      public class PropertyResourceReader {
          public static Map<String, String> map = new HashMap<>();
      
          public Map<String, String> readPropertyFile(String fileName) {
              Properties pro = new Properties();
              InputStream in = getClass().getResourceAsStream(fileName);
              try {
                  pro.load(in);
                  Iterator<String> iterator = pro.stringPropertyNames().iterator();
                  while (iterator.hasNext()) {
                      String key = iterator.next();
                      String value = pro.getProperty(key);
                      map.put(key, value);
                  }
                  in.close();
              } catch (IOException e) {
                  e.printStackTrace();
              }
              return map;
          }
      }

      工厂类:

      public class ProductFactory {
          public static Product produce(String key) throws Exception {
              PropertyResourceReader reader = new PropertyResourceReader();
              Map<String, String> map = reader.readPropertyFile("product.properties");
              try {
                  Product product = (Product) Class.forName(map.get(key)).newInstance();
                  return product;
              } catch (InstantiationException e) {
                  e.printStackTrace();
              } catch (IllegalAccessException e) {
                  e.printStackTrace();
              } catch (ClassNotFoundException e) {
                  e.printStackTrace();
              }
              throw new Exception("没有该产品");
          }
      }
      

    这个处理是不是很熟悉,没错,spring就是采用这个方式来进行实例bean的,spring中的spring-bean.xml相当与product,peoperties,spring中的XmlBeanDefinitionReader相当于此处的PropertyResourceReader,同样是将配置文件的内容读取到map中。

    • 优点

      提高代码的灵活度,将实例化对象的操作集中在工厂类中处理

    • 缺点

      每添加一个对象就需要对工厂类或者对配置文件进行修改,违背了不修改代码的原则。

  2. 工厂方法模式

    定义创建对象的接口,让子类去决定实例化类,工厂方法模式是一个类实例化延迟到子类。

    • 示例:

      定义一个工厂接口:

      public interface Factory {
       public Product produce();
      }

      再定义一个产品接口

      public interface Product{} 

      再定义子类来实现产品类,有子类来具体实现:

      public class Tv implements Product {
       public Tv() {
           System.out.println("电视被制造了");
       }
      }
      
      
      public class Refrigerator implements Product {
       public Refrigerator(){
           System.out.println("冰箱被制造了");
       }
      }

      工厂类:

      public class TvFactory implements Factory {
       @Override
       public Product produce() {
           return new Tv();
       }
      }
      
      public class RefrigeratorFactory implements Factory {
       @Override
       public Product produce() {
           return new Refrigerator();
       }
      }
      • 优点

      每种产品由一种工厂来创建,一个工厂保存一个new 基本完美,完全遵循 “不改代码”的原则,拓展性比较好

      • 缺点

      回出现成对的产品与工厂出现,新增一个产品将会对应的多出一个工厂。

  3. 抽象工厂模式

抽象工厂模式提供一个创建一系列或者相互依赖的对象接口,而不需要指定他们具体的类。

  • 实例

    定义两个接口进行分类

public interface Refrigerator {
}
public interface Tv {
}

再定义电视和冰箱的具体产品分类:

public class Meidi implements Refrigerator {
    public Meidi(){
        System.out.println("美的空调生产出来了");
    }
}

public class Hair implements Refrigerator {
    public Hair(){
        System.out.println("海尔空调生产出来了");
    }
}
public class LeTv implements Tv {
    public LeTv() {
        System.out.println("乐视电视被生产出来了");
    }
}

public class Sony implements Tv {
    public Sony(){
        System.out.println("索尼电视机被生产出来了");
    }
}

接下来定义工厂行为接口:

public interface Factory {
    public Tv produceTv();
    public Car produceCar();
}

具体工厂类

public class FactoryA implements Factory {
    @Override
    public Tv produceTv() {
        return new LeTv();
    }

    @Override
    public Refrigerator produceRefrigerator() {
        return new Hair();
    }
}
public class FactoryB implements Factory {

    @Override
    public Tv produceTv() {
        return new Sony();
    }

    @Override
    public Refrigerator produceRefrigerator() {
        return new Meidi();
    }
}

测试方法:

public class Test {
    public static void main(String[] args) {
        FactoryA factoryA = new FactoryA();
        factoryA.produceRefrigerator();

        FactoryB factoryB = new FactoryB();
        factoryB.produceTv();
    }
}
  • 优点:

    分类比较清晰,能保证客户端始终只使用一个产品族中的对象

  • 缺点:

    添加新产品的时候,需要修改工厂行为类,拓展比较差。

四、Spring IOC中使用工厂模式示例

上面也提到了Spring IOC 在解析配置文件的时候有用到工过工厂模(解析class核心是反射),下面具体举例说明一下,在解析spring的会有一个抽象类AbstractBeanFactory

先看下部分代码:


public abstract class AbstractFactoryBean<T>
        implements FactoryBean<T>, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
         // 定义了获取对象的前置判断工作,创建对象的工作则交给了一个抽象方法
// 这里判断了Bean是不是单例并且是否已经被加载过了(未初始化但加载过了,这个问题涉及到Spring处理循环依赖,以后会讨论到)
  public final T getObject() throws Exception {
        return this.isSingleton()?(this.initialized?this.singletonInstance:this.getEarlySingletonInstance()):this.createInstance();
    }
// 由子类负责具体创建对象
protected abstract T createInstance() throws Exception;

}

再看下AbstractFactoryBean类图:

Bean工厂有很多种,每个bean负责创建不同的Bean,比如可以让Bean拥有访问Spring容器的能力的工厂类BeanFactoryAware,创建比较负责的bean的工厂类BeanFactory

虽然子类可以自由创建bean,但是创建bean之前和之后对bean的处理,子类不需要关心,也没权利。就是他给了子类自由创建实例,但是又严格控制了实例创建前后的业务流程。

猜你喜欢

转载自blog.csdn.net/wagnteng/article/details/80473694