1.定义
提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们具体的类
2.借助(数据库访问)场景理解
2.1单类的时候,只需工厂方法模式
对象:用户
数据库:数据库:两种方式 SQLserver以及 Access
用工厂方法模式的数据库访问程序
(1)Iuser接口
package com.factory;
//IUSer接口,用于客户端访问,解除与具体数据库访问的耦合
public interface Iuser {
void Insert(User user);
User GetUser(int id);
}
(2)
package com.factory;
//用于访问Sql Server的User
public class SqlserverUser implements Iuser{
@Override
public void Insert(User user) {
System.out.println("在Sql Server中给User表增加一条记录");
}
@Override
public User GetUser(int id) {
System.out.println("在Sql Server中给根据ID得到User表的一条记录");
return null;
}
}
(3)
package com.factory;
//用于访问Access的User
public class AccessUser implements Iuser{
@Override
public void Insert(User user) {
System.out.println("在Access中给User表增加一条记录");
}
@Override
public User GetUser(int id) {
System.out.println("在Access中给根据ID得到User表的一条记录");
return null;
}
}
(4)
package com.factory;
//定义一个创建访问User表对象的抽象的工厂接口
public interface IFactory {
Iuser CreateUser();
}
(5)
package com.factory;
//实例化SqlserverUser
public class SqlServerFactory implements IFactory {
@Override
public Iuser CreateUser() {
return new SqlserverUser();
}
}
(6)
package com.factory;
public class AccessFactory implements IFactory{
@Override
public Iuser CreateUser() {
return new AccessUser();
}
}
(7)客户端代码
package com.factory;
public class AccessFactory implements IFactory{
@Override
public Iuser CreateUser() {
return new AccessUser();
}
}
(8)测试结果
在Sql Server中给User表增加一条记录
在Sql Server中给根据ID得到User表的一条记录
2.2多类的时候,体现抽象工厂模式
对象: 用户,以及部门
数据库:两种方式 SQLserver以及 Access
和2.1相比,增加如下代码
(1) 部门类
package com.abstractfactory;
public class Department {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
(2)Idepartment接口, 用于客户端访问,解除与具体数据库
package com.abstractfactory;
public interface Idepartment {
void Insert(Department department);
Department GetUser(int id);
}
(3)SqlServerDepartment类,用于Sqlserver操作department表
package com.abstractfactory;
public class SqlserverDepartment implements Idepartment{
@Override
public void Insert(Department department) {
System.out.println("在SqlServer中向department表插一条记录");
}
@Override
public Department GetUser(int id) {
System.out.println("在Sqlserver中给根据ID得到department表的一条记录");
return null;
}
}
(4)同理Accessdepartment
package com.abstractfactory;
public class AccessDepartment implements Idepartment{
@Override
public void Insert(Department department) {
System.out.println("在ACcess中向department表插一条记录");
}
@Override
public Department GetUser(int id) {
System.out.println("在Access中给根据ID得到department表的一条记录");
return null;
}
}
(5)修改Ifactory
package com.abstractfactory;
//定义一个创建访问User表对象的抽象的工厂接口
public interface IFactory {
Iuser CreateUser();
Idepartment CreateDepartment();
}
(6)修改SqlserverFactory
package com.abstractfactory;
//实例化SqlserverUser
public class SqlServerFactory implements IFactory {
@Override
public Iuser CreateUser() {
return new SqlserverUser();
}
@Override
public Idepartment CreateDepartment() {
return new SqlserverDepartment();
}
}
(7)修改AccessFactory
package com.abstractfactory;
public class AccessFactory implements IFactory {
@Override
public Iuser CreateUser() {
return new AccessUser();
}
@Override
public Idepartment CreateDepartment() {
return new AccessDepartment();
}
}
(8)客户端
package com.abstractfactory;
public class Client {
public static void main(String[] args) {
User user =new User();
Department department=new Department();
IFactory factory=new AccessFactory();//若要改变为Access数据库,只需将本句改为
// IFactory factory=new SqlServerFactory();
Iuser iuser=factory.CreateUser(); //与具体数据库访问解除了依赖
Idepartment idepartment=factory.CreateDepartment();
iuser.Insert(user);
iuser.GetUser(1);
idepartment.Insert(department);
idepartment.GetUser(1);
}
}
(9)测试结果
在Access中给User表增加一条记录
在Access中给根据ID得到User表的一条记录
在ACcess中向department表插一条记录
在Access中给根据ID得到department表的一条记录
3.抽象工厂模式优缺点
-
Ifactory中包含所有产品创建的抽象方法。
-
为创建不同的产品对象,客户端使用不同的具体工厂。
优点
- 便于交换产品系列,由于具体工厂类在一个应用中只需要在初始化的时候出现一次,使得改变一个应用的具体工厂变得非常容易,只需要改变具体工厂即可使用不同的产品配置
- 让具体的创建实例过程与客户端分离。客户端时通过他们的抽象接口比如Iuser操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中
缺点
增加实体类的时候要改动很多地方,比如增加company表,就需要增加ICompany接口,SqlserverFactory,AccessFactory,还需要改动Ifactory, SqlserverCompany以及AccessFactory
4.用简单工厂一定程度优化抽象工厂
设计Dataaccess类,
package com.simpleFactory;
public class DataAccess {
private static String db="SqlServer"; //在这里该数据库类型
//private static 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 CreateIdepartement(){
Idepartment result=null;
switch (db){
case "Sqlserver":
result=new SqlserverDepartment();
break;
case "Access":
result=new AccessDepartment();
break;
}
return result;
}
}
更改客户端
package com.simpleFactory;
public class Client {
public static void main(String[] args) {
User user =new User();
Department department=new Department();
//因为事先选好了用的数据库,所以可以直接得到数据库访问实例,客户不需要了解是用的什么数据库
Iuser iuser=DataAccess.CreateUser(); //因为设置的都是静态函数,直接用
Idepartment idepartment= (Idepartment) DataAccess.CreateIdepartement();
iuser.Insert(user);
iuser.GetUser(1);
idepartment.Insert(department);
idepartment.GetUser(1);
}
}
简单工厂方法的确实现了客户端不需要知道Sqlser和ACcess数据库, 但是如果再加一个数据库比如oracle,就不是抽象工厂方法中增加oracleFactory那么简单了,需要再DataAccess的每个函数中的switch中加Case
5.反射+抽象工厂模式
- 利用反射,使用字符串来实例化对象。而不再是写死再程序中
JAVA反射机制是就是运行的状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。通过反射机制可以动态的访问类的属性和方法以及字段。
最常用的反射机制就是:
(类)Class.forName("obj name").newInstance();
package com.reflection;
public class DataAccess {
private static String AssemblyName="com.reflection"; //根目录Src下的路径
private static String db="Sqlserver"; //可以替换成任意类型的数据库,比如access
public static Iuser CreateUser() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
String classname=AssemblyName+"."+db+"User";
return (Iuser)Class.forName(classname).newInstance();
//根据字符串 "com.reflection.SqlserverUser"匹配com.reflection.SqlserverUser类
}
public static Idepartment CreateIdepartment() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
String classname=AssemblyName+"."+db+"Department";
return (Idepartment) Class.forName(classname).newInstance();
}
}
成功的前提是com.reflection.SqlserverUser,SqlserverDepartment这些类存在
客户端没有变化
package com.reflection;
public class Client {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
User user =new User();
Department department=new Department();
Iuser iuser= DataAccess.CreateUser();
Idepartment idepartment= DataAccess.CreateIdepartment();
iuser.Insert(user);
iuser.GetUser(1);
idepartment.Insert(department);
idepartment.GetUser(1);
}
}
执行结果
在Sql Server中给User表增加一条记录
在Sql Server中给根据ID得到User表的一条记录
在SqlServer中向department表插一条记录
在Sqlserver中给根据ID得到department表的一条记录
6.用反射+配置文件+抽象工厂模式(end,最理想)
完整代码:
(1)实体类
package com.reflection;
public class User {
private int _id;
private String _name;
public int get_id() {
return _id;
}
public void set_id(int _id) {
this._id = _id;
}
public String get_name() {
return _name;
}
public void set_name(String _name) {
this._name = _name;
}
}
package com.reflection;
public class Department {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
(2) 实体表接口,事先客户端与实体表的解耦
package com.reflection;
//IUSer接口,用于客户端访问,解除与具体数据库访问的耦合
public interface Iuser {
void Insert(User user);
User GetUser(int id);
}
package com.reflection;
public interface Idepartment {
void Insert(Department department);
Department GetUser(int id);
}
(3) 具体数据库操作每个实体
Access数据库
package com.reflection;
//用于访问Access的User
public class AccessUser implements Iuser {
@Override
public void Insert(User user) {
System.out.println("在Access中给User表增加一条记录");
}
@Override
public User GetUser(int id) {
System.out.println("在Access中给根据ID得到User表的一条记录");
return null;
}
}
package com.reflection;
public class AccessDepartment implements Idepartment {
@Override
public void Insert(Department department) {
System.out.println("在ACcess中向department表插一条记录");
}
@Override
public Department GetUser(int id) {
System.out.println("在Access中给根据ID得到department表的一条记录");
return null;
}
}
Sql server数据库
package com.reflection;
//用于访问Sql Server的User
public class SqlserverUser implements Iuser {
@Override
public void Insert(User user) {
System.out.println("在Sql Server中给User表增加一条记录");
}
@Override
public User GetUser(int id) {
System.out.println("在Sql Server中给根据ID得到User表的一条记录");
return null;
}
}
package com.reflection;
public class SqlserverDepartment implements Idepartment {
@Override
public void Insert(Department department) {
System.out.println("在SqlServer中向department表插一条记录");
}
@Override
public Department GetUser(int id) {
System.out.println("在Sqlserver中给根据ID得到department表的一条记录");
return null;
}
}
(4) 数据库抽象工厂, 利用配置文件+反射
使用反射替代了简单工厂的switch
用户改数据库类型,只需在配置文件中改!
db=Access
package com.reflection;
import java.util.ResourceBundle;
public class DataAccess {
private static String AssemblyName="com.reflection";
//读取配置文件中的db类型
ResourceBundle resource1=ResourceBundle.getBundle("com/reflection/App");
//通过用户输入的来取指定类
private String db=resource1.getString("db"); //可以替换成任意类型的数据库,比如access
public Iuser CreateUser() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
String classname=AssemblyName+"."+db+"User";
return (Iuser)Class.forName(classname).newInstance();
}
public Idepartment CreateIdepartment() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
String classname=AssemblyName+"."+db+"Department";
return (Idepartment) Class.forName(classname).newInstance();
}
}
(5)客户端
package com.reflection;
public class Client {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
User user =new User();
Department department=new Department();
DataAccess dataAccess=new DataAccess();
Iuser iuser= dataAccess.CreateUser();
Idepartment idepartment= dataAccess.CreateIdepartment();
iuser.Insert(user);
iuser.GetUser(1);
idepartment.Insert(department);
idepartment.GetUser(1);
}
}
运行结果
在Access中给User表增加一条记录
在Access中给根据ID得到User表的一条记录
在ACcess中向department表插一条记录
在Access中给根据ID得到department表的一条记录