简单工厂

1. 使用场景

属于设计模式中的“生成器”模式,一般用来封装对象的创建过程,如果对象创建过程比较复杂,或者对于对象的创建有特殊需求(例如控制对象的创建个数等),都可以通过工厂模式来解决。同时应用工厂模式和接口可以用来来降低对象之间的耦合。

2. 实现举例

比如在设计Dao时,客户需要使用MySQL数据库,因此我们提供了UserDaoJdbc的实现类。但当我们的的项目卖给另一位客户时,客户要求上MongoDB数据库,这时又需要提供另一个UserDaoMongoDB的实现类。

如果不提前做出规划设计,直接在代码中引用了UserDaoJdbc的代码,那么需要改变实现类时,所有引用UserDaoJdbc的地方全部需要进行修改替换。一句话,可扩展性差,不灵活。

如何解决呢?要点是面向接口编程,并且把Dao对象的创建过程分离出去,交给工厂类来完成

1) 接口和实现代码:

interface UserDao { void save(User user); void update(User user); void delete(int id); User findById(int id); List<User> findAll(); } class UserDaoJdbc implements UserDao { // 具体实现略 } class UserDaoMongoDB implements UserDao { // 具体实现略 }

2) 配置文件(config.properties) :

interview.UserDao=interview.UserDaoMongoDB

3) 工厂类

class DaoFactory { static Map<Class<?>, Object> map = new HashMap<>(); static { try (InputStream is = DaoFactory.class.getResourceAsStream("config.properties")){ // 读取配置文件 Properties config = new Properties(); config.load(is); Enumeration<Object> e = config.keys(); while(e.hasMoreElements()) { // 获取接口名 String interfaceName = e.nextElement().toString(); // 获取实现类名 String implementClassName = config.getProperty(interfaceName); Class<?> interfaceClass = Class.forName(interfaceName); Class<?> implementClass = Class.forName(implementClassName); // 将接口.class作为key,实现类的实例对象作为值存入map map.put(interfaceClass, implementClass.newInstance()); } } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) { throw new Error(e); } } // 根据接口.class 获取实现类的实例对象 static <T> T getBean(Class<T> interfaceClass) { return interfaceClass.cast(map.get(interfaceClass)); } }

4) 调用代码

// 调用代码,只需要知道工厂和接口,无需知道(依赖于)实现类 UserDao userDao = DaoFactory.getBean(UserDao.class);

要点

  • 接口需要有
  • 将依赖关系定义放入一个配置文件
  • 工厂负责读取配置文件,根据配置选择实现类,创建对象实例

3. 不使用理由

工厂在设计时需要考虑很多事情:对象在创建时需不需要单例?需不需要延迟实例化?加不加控制反转?

现代的IOC容器(例如spring),已经充分考虑并实现了以上问题,更为完善和强大,因此推荐直接使用IOC容器。


results matching ""

    No results matching ""