1、抽象工厂模式(Abstract Factory),提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们的具体类。
2、抽象工厂模式结构图:
3、简单代码实现
书上例子主要是切换两个不同的数据库。
user和department实体类
public class User {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Department {
private String id;
private String deptName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
}
department和user持久层接口
interface IDepartment {
void insert(Department department);
Department getDepartment(int id);
}
public interface IUser {
void insert(User user);
User getUser(int id);
}
department持久层实现类,分为access类和sqlserver类;
public class AccessDepartment implements IDepartment {
@Override
public void insert(Department department) {
// TODO Auto-generated method stub
System.out.println("在Access中增加一条department数据");
}
@Override
public Department getDepartment(int id) {
// TODO Auto-generated method stub\
System.out.println("从Access中获取一条department数据");
return null;
}
}
public class SqlserverDepartment implements IDepartment {
@Override
public void insert(Department department) {
System.out.println("在Sqlserver中增加一条department数据");
}
@Override
public Department getDepartment(int id) {
System.out.println("从Sqlserver中获取一条department数据");
return null;
}
}
user持久层实现类,分为access类和sqlserver类;
public class AccessUser implements IUser {
@Override
public void insert(User user) {
// TODO Auto-generated method stub
System.out.println("在Access中增加一条user数据");
}
@Override
public User getUser(int id) {
System.out.println("从Access中获取一条user数据");
return null;
}
}
public class SqlserverUser implements IUser {
@Override
public void insert(User user) {
// TODO Auto-generated method stub
System.out.println("在Sqlserver中增加一条User数据");
}
@Override
public User getUser(int id) {
System.out.println("从Sqlserver中获取一条User数据");
return null;
}
}
IFactory接口,定义一个创建持久层表对象的抽象工厂类
public interface IFactory {
IUser createUser();
IDepartment createDepartment();
}
Sqlserver类,实现IFactory接口,实例化sqlserver类型的两个持久层对象
public class SqlserverFactory implements IFactory {
@Override
public IUser createUser() {
// TODO Auto-generated method stub
return new SqlserverUser();
}
@Override
public IDepartment createDepartment() {
// TODO Auto-generated method stub
return new SqlserverDepartment();
}
}
Accessserver类,实现IFactory接口,实例化Accessserver类型的两个持久层对象
public class AccessFactoy implements IFactory{
@Override
public IUser createUser() {
// TODO Auto-generated method stub
return new AccessUser();
}
@Override
public IDepartment createDepartment() {
// TODO Auto-generated method stub
return new AccessDepartment();
}
}
客户端代码
public class Client {
public static void main(String[] args) {
User user=new User();
Department dept=new Department();
//IFactory fa=new SqlserverFactory();
IFactory fa=new AccessFactoy();
IUser iu=fa.createUser();
iu.insert(user);
iu.getUser(1);
IDepartment id=fa.createDepartment();
id.insert(dept);
id.getDepartment(1);
}
}
抽象工厂模式的优缺点:
优点:
1、易于交换产品系列,具体工厂类,在一个应用中只需要在初始化的时候出现一次,这使得改变一个应用的具体工厂变得非常容易,只需改变工厂,便可以使用不同的产品配置。
2、他让具体的创建实例与客户端分离,客户端通过抽象接口操作实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码中
缺点:
1、当我们需要增加Project实体,需增加Iproject、sqlserverProject、AccessProject。还需要修改IFactory,SqlserverFactory,AccessFactory。
4、使用简单工厂方法改进上面的缺点
1、增加了dataAccess简单工厂类,客户端只需要createUser()和createDeptment() 。取代了IFactory、SqlserverFactory、AccessFactory。
public class DataAccess {
// private static final String DB="Sqlserver";
private static final String DB="Access";
public static IUser createUser() {
IUser result=null;
switch (DB){
case "Sqlserver":
result=new SqlserverUser();
break;
case "Access":
result=new AccessUser();
break;
}
return result;
}
public static IDepartment createDeptment() {
IDepartment result=null;
switch (DB){
case "Sqlserver":
result=new SqlserverDepartment();
break;
case "Access":
result=new AccessDepartment();
break;
}
return result;
}
}
客户端代码
public class Client2 {
public static void main(String[] args) {
User user=new User();
Department dept=new Department();
IUser iu=DataAccess.createUser();
iu.insert(user);
iu.getUser(1);
IDepartment id=DataAccess.createDeptment();
id.insert(dept);
id.getDepartment(1);
}
}
但是在添加需求和修改时仍需要修改dataAccess类的switch和case
5、使用反射来取代IFactory、SqlserverFactory、AccessFactory。
public class DataAccess2 {
private static final String PACKAGE="practice.AbstractFactory";
// private static final String DB="Sqlserver";
private static final String DB="Access";
public static IUser createUser() {
IUser result=null;
String className=PACKAGE+"."+DB+"User";
try {
result= (IUser) Class.forName(className).newInstance();
} catch (Exception e) {
}
return result;
}
public static IDepartment createDeptment() {
IDepartment result=null;
String className=PACKAGE+"."+DB+"Department";
try {
result= (IDepartment) Class.forName(className).newInstance();
} catch (Exception e) {
}
return result;
}
}
虽然解决了使用简单工厂出现的问题,但是在修改数据库是仍需要修改DB。
6、用反射加配置文件实现访问
添加一个config.properties
db=Access
修改后的dataAccess
public class DataAccess2 {
private static final String PACKAGE="practice.AbstractFactory";
// private static final String DB="Sqlserver";
private static String db="";
//使用properties文件配置
static {
Properties p=new Properties();
try {
p.load(new FileInputStream("src/practice/AbstractFactory/reflection/config.properties"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
db=p.getProperty("db");
}
public static IUser createUser() {
IUser result=null;
String className=PACKAGE+"."+db+"User";
try {
result= (IUser) Class.forName(className).newInstance();
} catch (Exception e) {
}
return result;
}
public static IDepartment createDeptment() {
IDepartment result=null;
String className=PACKAGE+"."+db+"Department";
try {
result= (IDepartment) Class.forName(className).newInstance();
} catch (Exception e) {
}
return result;
}
}
客户端代码同上。
哇,完美解决