简单工厂模式:创建一个工厂类,在类中通过具体条件选择实例化哪个类。
工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。
抽象工厂模式:提供一个创建一系列相关对象的接口,而无需指定他们具体的类。
举个例子说明这三个模式,目前有一个User类,它有两个方法,是用MySQL语法实现的。
public class User{ private int id; private String name; //get和set方法省略 } public class MysqlUser{ public void insertUser(User user){ //插入方法 } public User selectUser(int id){ //查找方法 } } 客户端调用 public static void main(String[] args){ User user = new User(); MysqlUser mysqlUser = new MysqlUser(); mysqlUser.insertUser(user); mysqlUser.selectUser(1); }如果现在要把数据库改成sqlServer该怎么办,需要修改大量客户端代码,代码对具体数据库的依赖程度太高,导致耦合性高。
现在用工厂模式实现,定义一个接口,让子类决定实例化哪个类,让业务逻辑与数据访问解耦。
public interface IUser{ void insertUser(User user); User selectUser(int id); } public class MysqlUser implements IUser{ public void insertUser(User user){ //MysqlUser插入方法 } public User selectUser(int id){ //MysqlUser查找方法 } } public class SqlserverUser implements IUser{ public void insertUser(User user){ //SqlserverUser插入方法 } public User selectUser(int id){ //SqlserverUser查找方法 } } 工厂类 public interface IFactory{ IUser createUser(); } public class MysqlFactory implements IFactory{ public IUser createUser(){ return new MysqlUser(); } } public class SqlserverFactory implements IFactory{ public IUser createUser(){ return new SqlserverUser(); } } 客户端 public static void main(String[] args){ User user = new User(); IFactory factory = new MysqlFactory(); IUser iu = factory.createUser(); iu.insertUser(); iu.selectUser(); }当切换数据库时只需修改工厂类的具体实例化即可,也就是new MysqlFactory()改为new SqlserverFactory()。如果在加上一个部门类及其方法该怎么办呢?仅仅只需要在IFactory中添加一个createDepartment()方法,再在具体的工厂实现类中加入创建部门的具体实现方法,并不影响客户端代码。这就变成了抽象工厂模式。
抽象工厂模式便于不同类型产品之间的切换,并且具体创建实例的过程与客户端分离,客户端通过抽象接口操纵实例,产品的具体类名也被具体的工厂实现分离,不会出现在客户端代码中。但是每次进行数据库的访问,都要加上一个IFactory factory = new MysqlFactory();下面用简单工厂模式来实现。
public class DbFactory{ private static db = "mysql"; //private static db = "sqlserver"; public static IUser createUser(){ IUser result = null; switch(db){ case "mysql": result = new mysqlUser(); case "sqlserver": result = new sqlserverUser(); } return result; } } 客户端 public static void main(String[] args){ User user = new User(); IUser iu = DbFactory.createUser(); iu.insertUser(user); iu.selectUser(1); }客户端中并没有出现具体数据库的名称,实现了解耦。只需在数据库工厂中进行切换db的值,但是如果现在在加上一个oracle数据库,DbFactory中每个方法的switch中都得加个case语句。下面用反射来实现
public class DbFactory{ private static db = "mysql"; //private static db = "sqlserver"; public static IUser createUser(){ String className = db + "User"; return (IUser)class.forName(className).newInstance(); } } 客户端代码同上到这个程度,已经非常简单了,切换数据库只需要修改db就可以了,但还是得修改程序,我们可以增加一个xml文件,将数据库的信息配置在xml中,在DbFactory中读取文件信息即可,这样每次只需要修改配置文件就可以了,不用修改程序,实现了完全的解耦。
这种通过反射的方式找到需要实例化类的方法就叫依赖注入,突然之间感觉对spring的理解又加深了,spring提供了一个专门的IOC容器,通过配置文件或者注解的方式将类注入进去,当其他的类需要调用注入到spring中的类时,只需要加上@Autowired这个注解,spring就相当于是一个中间容器,解除了类与类之间的耦合。