这里又出现了一个抽象工厂模式,这个抽象工厂模式又是什么呢?sql
咱们如今来模拟一个场景,如今用的是Mysql数据库,明天让你更换为Oracle数据库。此时,想一想要作多少的改动。但咱们若是用工厂模式,这会让你节省大量时间。数据库
首先,咱们用工厂方法模式来设计这个程序。框架
咱们画出类的UML图。ide
IFactory做为工厂类的接口,有两个子类,分别用来构造不一样的实例。spa
IFactory工厂接口代码以下:设计
package day_3_facoryMethod_db; /** * 数据库工厂类 * @author turbo * * 2016年9月6日 */ public interface IFactory { IUser createUser(); }
MysqlFactory代码以下,省去OracleFactory。code
package day_3_facoryMethod_db; /** * @author turbo * * 2016年9月6日 */ public class MysqlFactory implements IFactory { /* (non-Javadoc) * @see day_3_facoryMethod_db.IFactory#createUser() */ @Override public IUser createUser() { return new MysqlUser(); } }
IUser是对User表操做的接口,不一样数据库的操做只需继承实现它便可。对象
package day_3_facoryMethod_db; /** * 操做数据库User表的接口 * @author turbo * * 2016年9月6日 */ public interface IUser { void insert(User user); User getUserById(int userId); }
MysqlUser是对IUser接口的实现,是对User表操做的具体实现。省去OracleUser。blog
package day_3_facoryMethod_db; /** * Mysql对User表的操做 * @author turbo * * 2016年9月6日 */ public class MysqlUser implements IUser { /* (non-Javadoc) * @see day_3_facoryMethod_db.IUser#insert(day_3_facoryMethod_db.User) */ @Override public void insert(User user) { System.out.println("插入一条数据"); } /* (non-Javadoc) * @see day_3_facoryMethod_db.IUser#getUserById(int) */ @Override public User getUserById(int userId) { System.out.println("获取一条数据"); return null; } }
如今经过客户端代码来观察是如何作到业务逻辑和数据访问的解耦的。继承
package day_3_facoryMethod_db; /** * 客户端 * @author turbo * * 2016年9月6日 */ public class Main { public static void main(String[] args){ IFactory factory = new MysqlFactory(); //若是须要修改数据库,则只需将new MysqlFactory()修改成new OracleFactory()。 IUser iu = factory.createUser(); iu.insert(new User()); iu.getUserById(1); } }
若是要更改数据库,则只需将new MysqlFactory()修改成new OracleFactory()便可,这就是所谓的业务逻辑和数据访问的解耦。
上面咱们实际上从新回顾了工厂方法模式,彷佛已经达到了咱们想要的效果。可是,数据库里不止一张表,两个数据库又是两大不一样分类,解决这种涉及多个产品系列的问题,有一个专门的工厂模式叫抽象工厂模式。因此实际上,若是增长一个新表,上面的工厂方法模式就有了一个新的名字——抽象工厂模式。
抽象工厂模式:提供一个建立一些列有关或互相依赖对象的接口,而无需制定它们具体的类。
下面咱们进阶一下:用反射+抽象工厂的方式来设计这个程序。
是否记得在简单工厂模式中,咱们用到了switch或者if。有用到switch和if的地方,咱们均可以考虑利用反射技术来去除,以解除分支带来的耦合。
这其实将会引伸一个概念:依赖注入(DI),或者称为控制反转,将传统上由程序代码直接操控的对象的调用权交给容器,经过容器来实现对象组件的装配和管理,什么意思?就是直观上代码里看不到new 对象,这个操做交给了外部容器,这样将会大大下降程序的耦合性。好比:Spring框架的IoC容器。
咱们先来看若是要实例化上面的的IUser会怎么作?
IUser iu = new MysqlUser();
若是是用反射呢?
Class classType = Class.forName("day_3_facoryMethod_db.MysqlUser"); //“类所在的包名.类名”
Object obj = classType.newInstance();
咱们对obj作验证。
System.out.println(obj instanceof MysqlUser);
输出为true,用反射机制成功实例化对象。
反射和直接new有什么区别呢?答案就在于:反射使用的字符串,也就是说能够用变量来处理。而new的常规方法是已经编译好了的,不能随意灵活更换其实例化对象。因此,思考,若是咱们用配置文件的方式,是否是能灵活替换咱们想要的实例化对象呢?