设计模式——抽象工厂模式
@author 无忧少年
@createTime 2019/10/16
抽象工厂模式:提供一个 创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
抽象工厂模式(Abstract Factory)结构图
抽象工厂模式代码示例:
// 用户接口
public interface IUser {
void Insert(User user);
void GetUser(String id);
}
// 访问MySql的User
public class MySqlUser implements IUser {
@Override
public void Insert(User user) {
System.out.println("在MySql中给User表新增一条数据");
}
@Override
public void GetUser(String id) {
System.out.println("在MySql中根据id查询User表的一条数据");
}
}
// 访问SqlServer的User
public class SqlServerUser implements IUser {
@Override
public void Insert(User user) {
System.out.println("在sql server中给User表新增一条数据");
}
@Override
public void GetUser(String id) {
System.out.println("在sql server中根据id查询User表的一条数据");
}
}
// Department接口
public interface IDepartment {
void insert(Department department);
Department getDepartmentById(String id);
}
// 访问MySql的Departmen
public class MySqlDepartment implements IDepartment {
@Override
public void insert(Department department) {
System.out.println("在MySql中给department表新增一条数据");
}
@Override
public Department getDepartmentById(String id) {
System.out.println("在MySql中根据id查询department表的一条数据");
return null;
}
}
// 访问SqlServer的Department
public class SqlserverDepartment implements IDepartment {
@Override
public void insert(Department department) {
System.out.println("在sql server中给department表新增一条数据");
}
@Override
public Department getDepartmentById(String id) {
System.out.println("在sql server中根据id查询department表的一条数据");
return null;
}
}
// 抽象工厂接口
public interface IFactory {
IUser CreteUser();
IDepartment CreateDepartment();
}
// 实现IFactory接口 实例化MySqlUser和MySqlDepartment
public class MySqlFactory implements IFactory {
@Override
public IUser CreteUser() {
return new MySqlUser();
}
@Override
public IDepartment CreateDepartment() {
return new MySqlDepartment();
}
}
// 实现IFactory接口 实例化SqlServerUser和SqlServerDepartment
public class SqlServerFactory implements IFactory {
@Override
public IUser CreteUser() {
return new SqlServerUser();
}
@Override
public IDepartment CreateDepartment() {
return new SqlserverDepartment();
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
User user =new User();
Department department=new Department();
IFactory factory =new SqlServerFactory();
IUser iu=factory.CreteUser();
iu.Insert(user);
iu.GetUser("1");
IDepartment id = factory.CreateDepartment();
id.insert(department);
id.getDepartmentById("1");
}
}
// 控制台输出
在sql server中给User表新增一条数据
在sql server中根据id查询User表的一条数据
在sql server中给department表新增一条数据
在sql server中根据id查询department表的一条数据
这样可以做到只需要更改IFactory factory =new SqlServerFactory()IFactory factory =new MySqlFactory() 就是先了数据库访问的切换了
抽象工厂模式也有缺点,当每次需要声明ProductA 1的时候都需要先声明ConcreteFactory1,然后才能创建ProductA 1的实例,或者如果说需要增加一个类,那么也是需要改动AbstractFactory、ConcreteFactory1和ConcreteFactory2三个类,这样就太糟糕了,编程是一门艺术,这样大批量的改动,明显是非常丑陋的做法,所以可以根据简单工厂模式来改进抽象工厂。
结构图
代码示例
//简单工厂
public class DataAccess {
private static String db="SQLSERVER";// 数据库名称,可以替换成MYSQL
// private static String db="MYSQL";
public static IUser CreateUser(){
IUser result =null;
switch (db){
case "SQLSERVER":
result = new SqlServerUser();
break;
case "MYSQL":
result= new MySqlUser();
break;
}
return result;
}
public static IDepartment CreateDepartment(){
IDepartment result =null;
switch (db){
case "SQLSERVER":
result = new SqlserverDepartment();
break;
case "MYSQL":
result= new MySqlDepartment();
break;
}
return result;
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
User user = new User();
Department department = new Department();
IUser iu = DataAccess.CreateUser();
iu.Insert(user);
iu.GetUser("1");
IDepartment id = DataAccess.CreateDepartment();
id.insert(department);
id.getDepartmentById("1");
}
}
// 控制台输出
在sql server中给User表新增一条数据
在sql server中根据id查询User表的一条数据
在sql server中给department表新增一条数据
在sql server中根据id查询department表的一条数据
这里使用一个简单工厂类 DataAccess替代了原先的IFactory,SqlServerFactory,SqlServerFactory三个类,改变常量db的值即可在两个数据库做切换, 客户端也没有出现Mysql或者SqlServer字样,达到了解耦的目的。现在如果还要增加一个ORACL数据库,那么需要在DataAccess的每个方法中的switch都新增一个case。
可以使用反射+抽象工厂的数据访问程序
代码示例
// 使用反射技术
public class DataAccess {
// 包路径
private final static String AssembleName="abstractfactory";
// 数据库名
private final static String db="SqlServer";
// private static String db="Mysql";
public static IUser CreateUser(){
IUser result =null;
String className=AssembleName+"."+db+"User";
try{
Class clz = Class.forName(className);
result = (IUser)clz.newInstance();
}catch (Exception e){
}
return result;
}
public static IDepartment CreateDepartment(){
IDepartment result =null;
String className=AssembleName+"."+db+"Department";
try{
Class clz = Class.forName(className);
result = (IDepartment)clz.newInstance();
}catch (Exception e){
}
return result;
}
}
// 客户端
public class Main {
public static void main(String[] args) {
User user = new User();
Department department = new Department();
IUser iu = DataAccess.CreateUser();
iu.Insert(user);
iu.GetUser("1");
IDepartment id = DataAccess.CreateDepartment();
id.insert(department);
id.getDepartmentById("1");
}
}
// 控制台输出
在sql server中给User表新增一条数据
在sql server中根据id查询User表的一条数据
在sql server中给department表新增一条数据
在sql server中根据id查询department表的一条数据
其中的数据库名也可以放在配置文件中进行配置, 即使用反射+配置文件实现数据访问程序,这里就不做例子了,和上述反射技术差不多。只是将数据库名提到配置文件中