一、概念及类图
1、简单工厂模式(静态工厂模式)
在简单工厂模式中,工厂类可以根据参数的不同返回不同的类的实例。
2、工厂方法模式(多态模式)
工厂方法模式的核心是抽象工厂类Factory,各种具体工厂类继承抽象工厂类并实现在抽象工厂类中定义的工厂方法,从而让客户只关心抽象产品和抽象工厂,不用管具体返回的是哪一种具体产品,也不用关心它是如何被具体工厂创建的。
3、抽象工厂模式
该模式提供了一个创建一系列相关或相互依赖对象的接口。
二、简单工厂模式与工厂方法模式实例
1、简单工厂模式—简单计算器
//抽象运算类---
public abstract class Operation {
private double numberA=0;
private double numberB=0;
public double getNumberA() {
return numberA;
}
public void setNumberA(double numberA) {
this.numberA = numberA;
}
public double getNumberB() {
return numberB;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
public abstract double GetResult();
}
//加法类
public class OperationAdd extends Operation{
@Override
public double GetResult() {
// TODO Auto-generated method stub
double result=0;
result=getNumberA()+getNumberB();
return result;
}
}
//除法类
public class OperationDiv extends Operation{
@Override
public double GetResult() {
double result=0;
result=getNumberA()/getNumberB();
return result;
}
}
//乘法类
public class OperationMul extends Operation{
@Override
public double GetResult() {
double result=0;
result=getNumberA()*getNumberB();
return result;
}
}
//减法类
public class OperationSub extends Operation{
@Override
public double GetResult() {
// TODO Auto-generated method stub
double result=0;
result=getNumberA()-getNumberB();
return result;
}
}
/**
* 运算工厂类---根据运算符的不同来创建不同实例对象
*
*/
public class OperationFactory {
public static Operation createOperation(String operate){
Operation operation=null;
switch (operate) {
case "+":
operation=new OperationAdd();
break;
case "-":
operation=new OperationSub();
break;
case "*":
operation=new OperationMul();
break;
case "/":
operation=new OperationDiv();
break;
}
return operation;
}
}
//客户端
public class Show {
public static void main(String[] args) {
System.out.println("请输入数字A:");
Scanner sc=new Scanner(System.in);
String strNumberA=sc.nextLine();
System.out.println("请输入运算符(+,-,*,/):");
String strOperate=sc.nextLine();
System.out.println("请输入数字B:");
String strNumberB=sc.nextLine();
Operation operation = OperationFactory.createOperation(strOperate);
operation.setNumberA(Double.parseDouble(strNumberA));
operation.setNumberB(Double.parseDouble(strNumberB));
double result = operation.GetResult();
System.out.println("结果为:"+result);
sc.close();
}
}
2、工厂方法模式—简单计算器
/*
* 工厂接口
*/
public interface IFactory {
Operation CreateOperation();
}
/*
* 加法类工厂
*/
public class AddFactory implements IFactory{
@Override
public Operation CreateOperation() {
return new OperationAdd();
}
}
/*
* 除法类工厂
*/
public class DivFactory implements IFactory{
@Override
public Operation CreateOperation() {
return new OperationDiv();
}
}
/*
* 乘法类工厂
*/
public class MulFactory implements IFactory{
@Override
public Operation CreateOperation() {
return new OperationMul();
}
}
/*
* 减法类工厂
*/
public class SubFactory implements IFactory{
@Override
public Operation CreateOperation() {
return new OperationSub();
}
}
//运算类
public abstract class Operation {
private double numberA=0;
private double numberB=0;
public double getNumberA() {
return numberA;
}
public void setNumberA(double numberA) {
this.numberA = numberA;
}
public double getNumberB() {
return numberB;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
public abstract double GetResult();
}
//加法类
public class OperationAdd extends Operation{
@Override
public double GetResult() {
// TODO Auto-generated method stub
double result=0;
result=getNumberA()+getNumberB();
return result;
}
}
//除法类
public class OperationDiv extends Operation{
@Override
public double GetResult() {
double result=0;
result=getNumberA()/getNumberB();
return result;
}
}
//乘法类
public class OperationMul extends Operation{
@Override
public double GetResult() {
double result=0;
result=getNumberA()*getNumberB();
return result;
}
}
//减法类
public class OperationSub extends Operation{
@Override
public double GetResult() {
// TODO Auto-generated method stub
double result=0;
result=getNumberA()-getNumberB();
return result;
}
}
/*
* 客户端展示----工厂方法模式实现简单计算器
*/
public class Show {
public static void main(String[] args) {
IFactory iFactory=new AddFactory();
Operation operation=iFactory.CreateOperation();
operation.setNumberA(1);
operation.setNumberB(2);
double result=operation.GetResult();
System.out.println("结果: "+result);
}
}
三、抽象工厂模式实例之数据库访问程序
(1)、版本1
//客户端
public class Client {
public static void main(String[] args) {
User user=new User();
SqlserverUser sqlserverUser=new SqlserverUser();
sqlserverUser.Insert(user);
sqlserverUser.GetUser(1);
}
}
//sql Server数据库操作user
public class SqlserverUser {
public void Insert(User user){
System.out.println("SQL Server中給User表添加一條記錄");
}
public User GetUser(int id){
System.out.println("SQL Server中根據id得到User表中的一條記錄");
return null;
}
}
//用户对象
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;
}
}
分析:这里因为SqlserverUser sqlserverUser=new SqlserverUser();这行代码写死在SqlServer了,即没有灵活性,如果这里具有灵活性(多态),那么在执行sqlserverUser.Insert(user);sqlserverUser.GetUser(1);这两句代码时就不用考虑是哪个数据库了。
(2)、版本二—>使用抽象工厂模式。
//用户接口--->抽象产品A
public interface IUser {
void InsertUser(User user);
User GetUser(int id);
}
//部门接口--->抽象产品B
public interface IDepartment {
void Insert(Department department);
Department GetDeparment(int id);
}
//抽象工厂
public interface IFactory {
IUser CreateUser();
IDepartment createDepartment();
}
//Access数据库访问--->具体工厂1
public class AccessFactory implements IFactory{
@Override
public IUser CreateUser() {
return new AccessUser();//类的实例化放在子类中,封装new AccessUser()所造成的变化
}
@Override
public IDepartment createDepartment() {
return new AccessDepartment();
}
}
//SqlServer数据库--->具体工厂2
public class SqlServerFactory implements IFactory{
@Override
public IUser CreateUser() {
return new SqlserverUser();
}
@Override
public IDepartment createDepartment() {
return new SqlserverDepartment();
}
}
//具体产品类A
public class SqlserverUser implements IUser{
@Override
public void InsertUser(User user) {
System.out.println("SQL Server中給User表添加一條記錄");
}
@Override
public User GetUser(int id) {
System.out.println("SQL Server中根據id得到User表中的一條記錄");
return null;
}
}
//具体产品类A
public class AccessUser implements IUser{
@Override
public void InsertUser(User user) {
System.out.println("在Access中給User表添加一條記錄");
}
@Override
public User GetUser(int id) {
System.out.println("在Access中根據id查找User表的一條記錄");
return null;
}
}
//具体产品类B
public class SqlserverDepartment implements IDepartment{
@Override
public void Insert(Department department) {
System.out.println("在SQL Server中給department表新增一條記錄");
}
@Override
public Department GetDeparment(int id) {
System.out.println("在SQL Server中根據id從department表中取出一條記錄");
return null;
}
}
//具体产品类B
public class AccessDepartment implements IDepartment{
@Override
public void Insert(Department department) {
System.out.println("在Access中給Department表新增一條記錄");
}
@Override
public Department GetDeparment(int id) {
System.out.println("在Access中根據id得到department表中的一條記錄");
return null;
}
}
//用户类
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;
}
}
//客户端
public class Client {
public static void main(String[] args) {
User user=new User();
IFactory factory=new SqlServerFactory();
IUser iUser=factory.CreateUser();
iUser.InsertUser(user);
iUser.GetUser(1);
Department department=new Department();
IDepartment iDepartment=factory.createDepartment();
iDepartment.Insert(department);
iDepartment.GetDeparment(1);
}
}
分析:
1、在使用了抽象工厂模式后,通过IFactory factory=new SqlServerFactory();这行代码来实现数据库的切换。
2、如果要新增一个表对象(抽象产品),则需要大量的改动。
(3)、版本三—>借助简单工厂改进抽象工厂
去掉原有的IFactory抽象工厂即两个具体工厂,用下面的DataAccess类来代替。
public class DataAccess {
private static String db="Sqlserver";
// private static String db="Access";
/*
* 根据db来决定实例化不同的类
*/
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 CreateDepartment(){
IDepartment result=null;
switch (db) {
case "Sqlserver":
result=new SqlserverDepartment();
break;
case "Access":
result=new AccessDepartment();
break;
}
return result;
}
}
public class Client {
public static void main(String[] args) {
User user=new User();
Department department=new Department();
IUser iUser=DataAccess.CreateUser();//直接通过DataAccess获得想要的表对象
iUser.InsertUser(user);
iUser.GetUser(1);
IDepartment iDepartment=DataAccess.CreateDepartment();
iDepartment.Insert(department);
iDepartment.GetDeparment(1);
}
}
分析:这样把表对象的创建放入DataAccess中,在DataAccess中通过db来判断此时是哪一个数据库,从而实例化相应的表对象,当需要修改数据库时,只需要改动db即可。另外,在DataAccess中有大量的分支判断,代码可以通过反射进一步优化,让db变量的值在客户端被指定,而不是事前就在DataAccess中写出。
// 数据库名称
private static String db = "Sqlserver";
// 包名----》改成SqlserverDepartment等类所在的包名
private static String AssemblyName = "com.hwj.www.model15.version4.";
/*
* 根据db来决定实例化不同的类
*/
public static IUser CreateUser() throws Exception {
IUser result = null;
//通过反射来实例化相应
result = (IUser) Class.forName(AssemblyName + db + "User").newInstance();//SqlserverUser AccessUser
return result;
}
public static IDepartment CreateDepartment() throws Exception {
IDepartment result = null;
result = (IDepartment) Class.forName(AssemblyName + db + "Department").newInstance();//SqlserverDepartment AccessDepartment
return result;
}
}
三、总结
1、简单工厂模式中,工厂Factory类集中了所有产品创建的逻辑,一旦要拓展新产品时,就不得不修改工厂类,这就违反了开闭原则(对拓展开放,对修改封闭),并且会造成工厂的逻辑过于复杂。
2、工厂方法模式中,在新增一个新产品时,就要新增一个具体工厂和一个具体产品类,这样程序的拓展性就有了提高,符合了开闭原则,避免了简单工厂模式的缺点,但是呢,新增产品时需要新增两个类,会增加代码量,可谓是有舍有得,具体如何要结合具体情况来使用。
3、抽象工厂模式是所有工厂模式的一般形式,当抽象工厂模式退化到只有一个产品登级结构时,就变成了工厂方法模式。当工厂方法模式的工厂类只有一个时,且工厂方法为静态方法时,则又变成了简单工厂模式。与工厂方法模式相似,抽象工厂模式隔离了具体类的生成,让客户端不清楚具体什么样的对象被创建。
Among thousands of people, you meet those you’ve met. Through thousands of years, with the boundlessness of time, you happen to meet them, neither earlier nor a bit too late.