设计模式-抽象工厂模式
概念
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据里氏替换原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。
优点
1、抽象工厂模式隔离了具体类的生产,使得客户并不需要知道什么被创建。
2、当一个产品族中(使用Mysql数据库)的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
3、增加新的具体工厂和产品族(比如添加DB2)很方便,无须修改已有系统,符合“开闭原则”。
缺点
1、如果产品族比较多的情况下,会产生很多的类
2、如果不适用反射技术,那么可能会违背开闭原则
3、如果采用反射技术,受强制命名规范的限制
角色
SuperFactory:超级工厂
ProductA: 抽象产品A
ProductB:产品B
ConreteProductA:具体产品A
ConreteProductB:具体产品B
使用场景
系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
UML类图
代码解析UML类图
SuperFactory:超级工厂
/** * 设计模式-抽象工厂模式-超级工厂(创建多种抽象产品的工厂) * * 原本需要写多个工厂,这里简化了方式,使用一个工厂生产多个抽象产品 * * 这里是根据数据源的不同,生产出不同产品(多个抽象产品,ISysRoleDao ISysUserDao )的 * 不同具体产品(ISysRoleDao ISysUserDao的所有实现类) * * Created by laizhiyuan on 2017/6/9. */ public abstract class DaoFactory { /** * 配置文件获取配置的数据源类型 */ private static String dbType = PropertiesHelper.getValueByKey("db.type"); /** * 项目包根路径 */ private static String basePagePath = PropertiesHelper.getValueByKey("daoRootPagePath"); /** * 抽象产品 ISysRoleDao * * @return */ public static ISysRoleDao newISysRoleDaoInstance(){ String classPath; ISysRoleDao sysRoleDao; try { /** * 如果有子包,可以在这里拼接上去 */ classPath = basePagePath + "." + dbType + "SysRoleDao"; sysRoleDao = (ISysRoleDao) Class.forName(classPath).newInstance(); } catch (Exception e) { /** * 默认使用Mysql */ sysRoleDao = new MysqlSysRoleDao(); } return sysRoleDao; } /** * 抽象产品 ISysUserDao * @return */ public static ISysUserDao newISysUserDaoInstance() { String classPath; ISysUserDao sysUserDao; try { /** * 如果有子包,可以在这里拼接上去 */ classPath = basePagePath + "." + dbType + "SysUserDao"; sysUserDao = (ISysUserDao) Class.forName(classPath).newInstance(); } catch (Exception e) { /** * 默认使用Mysql */ sysUserDao = new MysqlSysUserDao(); } return sysUserDao; } }
Product: 抽象产品A、B、C ...
/** * 设计模式-抽象工厂模式-抽象产品(IBaseDao) * * 抽象产品 BaseDao * * Created by laizhiyuan on 2017/6/9. */ public interface IBaseDao<T> { /** * 增 * * @param t * @return */ public abstract int insert(T t); /** * 删 * * @param id * @return */ public abstract int deleteById(String id); /** * 查 * * @param id * @return */ public abstract T selectById(String id); /** * 改 * * @param t * @return */ public abstract int update(T t); }
/** * 设计模式-抽象工厂模式-抽象产品(ISysRoleDao) * * Created by laizhiyuan on 2017/6/9. */ public interface ISysRoleDao extends IBaseDao<SysRole> { }
/** * 设计模式-抽象工厂模式-抽象产品(ISysUserDao) * * 这里是系统用户表数据层 * * Created by laizhiyuan on 2017/6/9. */ public interface ISysUserDao extends IBaseDao<SysUser> { }
ConreteProduct:具体产品A\B\C等等
/** * * 设计模式-抽象工厂模式-具体产品 * * MongoDb 数据源时使用的BaseDao * * Created by laizhiyaun on 2017/6/9. */ public class MongoBaseDao<T> implements IBaseDao<T> { @Override public int insert(T t) { System.out.println("使用db.tableName.save语句插入" + t.getClass().getSimpleName()); return 0; } @Override public int deleteById(String id) { System.out.println("使用db.tableName.remove语句删除"); return 0; } @Override public T selectById(String id) { System.out.println("使用db.tableName.find语句查询"); return null; } @Override public int update(T t) { System.out.println("使用db.tableName.update语句修改"); return 0; } }
/** * 设计模式-抽象工厂模式-具体产品 * * Created by laizhiyuan on 2017/6/9. */ public class MongoSysRoleDao extends MongoBaseDao<SysRole> implements ISysRoleDao{ }
/** * * * Created by laizhiyuan on 2017/6/9. */ public class MongoSysUserDao extends MongoBaseDao<SysUser> implements ISysUserDao{ }
/** * 设计模式-抽象工厂模式-具体产品 * * mysql 数据源时使用的BaseDao * * Created by laizhiyuan on 2017/6/9. */ public class MysqlBaseDao<T> implements IBaseDao<T> { @Override public int insert(T t) { System.out.println("使用insert into语句插入" + t.getClass().getSimpleName()); return 1; } @Override public int deleteById(String id) { System.out.println("使用delete from 语句删除"); return 1; } @Override public T selectById(String id) { System.out.println("使用select * from 语句查询"); return null; } @Override public int update(T t) { System.out.println("使用update 语句修改"); return 1; } }
/** * Created by laizhiyuan on 2017/6/9. */ public class MysqlSysRoleDao extends MysqlBaseDao<SysRole> implements ISysRoleDao { }
/** * Created by laizhiyuan on 2017/6/9. */ public class MysqlSysUserDao extends MysqlBaseDao<SysUser> implements ISysUserDao { }
业务类
/** * * Created by laizhiyuan on 2017/6/9. */ public class SysRole implements Serializable{ static final long serialVersionUID = 42L; private long id; private String name; private List<SysUser> userList = new ArrayList<SysUser>(); public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<SysUser> getUserList() { return userList; } public void setUserList(List<SysUser> userList) { this.userList = userList; } }
/** * Created by laizhiyuan on 2017/6/9. */ public class SysUser implements Serializable{ static final long serialVersionUID = 42L; private List<SysRole> roleList = new ArrayList<SysRole>(); private long id; private String name; private String pwd; public List<SysRole> getRoleList() { return roleList; } public void setRoleList(List<SysRole> roleList) { this.roleList = roleList; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public String toString() { return "SysUser{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } }
工具类
/** * 配置文件工具类 * * Created by laizhiyuan on 2017/6/9. */ public abstract class PropertiesHelper { public static String propertiesFilePath; /** * 通过key获得值 * * @param key * @return */ public static String getValueByKey(String key){ if (propertiesFilePath == null || "".equals(propertiesFilePath)){ propertiesFilePath = "sys_conf.properties"; } Properties properties = new Properties(); try { properties.load(PropertiesHelper.class.getClassLoader().getResourceAsStream(propertiesFilePath)); } catch (IOException e) { e.printStackTrace(); } return (String) properties.get(key); } public static void main(String[] args) { String test = getValueByKey("db.baseDaoClassname"); System.out.println(test); } }
sys_conf.properties文件
# 这里根据你的路径填写 DAO层根路径 daoRootPagePath=com.lzy.study.pattrens.abstractFactoryPattern db.type=Mongo
测试
/** * 测试 * * Created by laizhiyuan on 2017/6/9. */ public class Main { /** * 客户端代码 * * 问:如果某天更换数据库为MongoDB,改怎么做呢? * 答:把sys_conf.properties文件的db.type的值改为Mongo就可以了 * * * 问:如果把数据库改为DB2需要改动什么呢?客户端代码需要改变吗? * 答:客户端不需要做任何改变,只需在daoRootPagePath路径下添加DB2BaseDao/DB2SysUserDao/DB2SysRoleDao, * DaoFactory添加创建DB2实例的工厂方法即可 * * @param args */ public static void main(String[] args) { SysUser sysUser = new SysUser(); sysUser.setName("laizhiyuan"); sysUser.setId(1); ISysUserDao sysUserDao = DaoFactory.newISysUserDaoInstance(); sysUserDao.insert(sysUser); SysRole sysRole = new SysRole(); sysRole.setId(1); sysRole.setName("admin"); ISysRoleDao sysRoleDao = DaoFactory.newISysRoleDaoInstance(); sysRoleDao.insert(sysRole); } }