創(chuàng)建類模式隱藏了這些類的實(shí)例是如何被創(chuàng)建和放在一起,整個(gè)系統(tǒng)關(guān)于這些對(duì)象所知道的是由抽象類所定義的接口;這樣,創(chuàng)建類模式在創(chuàng)建了什么,誰(shuí)創(chuàng)建它的,它怎么被創(chuàng)建的,以及何時(shí)創(chuàng)建這些方面提供了很大的靈活性。創(chuàng)建類模式抽象了實(shí)例化的過(guò)程,允許客戶用結(jié)構(gòu)和功能差別很大的“產(chǎn)品”對(duì)象配置一個(gè)系統(tǒng)配置可以是靜態(tài)的,即在編譯時(shí)指定,也可以是動(dòng)態(tài)的,就是運(yùn)行時(shí)再指定。
一、簡(jiǎn)單工廠模式:
需要增加運(yùn)算形式時(shí)只需要增加運(yùn)算子類,同時(shí)修改簡(jiǎn)單工廠中的switch增加分支即可,這樣客戶端調(diào)用代碼基本不動(dòng)。
// 運(yùn)算類 public class Operation { PRivate double _numberA = 0; private double _numberB = 0; // 數(shù)字A屬性public double NumberA { get { return _numberA; } set { _numberA = value; } } // 數(shù)字B屬性 public double NumberB { get { return _numberB; } set { _numberB = value; } } // 得到運(yùn)算結(jié)果 public virtual double getResult() { double result = 0; return result; } }// 加法類 class OperationAdd : Operation { public override double getResult() { double result = 0; result = NumberA + NumberB; return result; } } // 減法類 class OperationSub : Operation { public override double getResult() { double result = 0; result = NumberA - NumberB; return result; } } // 乘法類 class OperationMul : Operation { public override double getResult() { double result = 0; result = NumberA * NumberB; return result; } } // 除法類 class OperationDiv : Operation { public override double getResult() { double result = 0; if (NumberB==0) throw new Exception("除數(shù)不能為0。"); result = NumberA / NumberB; return result; } }// 簡(jiǎn)單類工廠 class OperationFactory { public static Operation createOperate(string operate) { Operation oper = null; switch (operate) { case "+": { oper = new OperationAdd(); break; } case "-": { oper = new OperationSub(); break; } case "*": { oper = new OperationMul(); break; } case "/": { oper = new OperationDiv(); break; } } return oper; } }//控制臺(tái)調(diào)用static void Main(string[] args) { try { Console.Write("請(qǐng)輸入數(shù)字A:"); string strNumberA = Console.ReadLine(); Console.Write("請(qǐng)選擇運(yùn)算符號(hào)(+、-、*、/):"); string strOperate = Console.ReadLine(); Console.Write("請(qǐng)輸入數(shù)字B:"); string strNumberB = Console.ReadLine(); string strResult = ""; Operation oper; //聲明運(yùn)算類 oper = OperationFactory.createOperate(strOperate); //根據(jù)運(yùn)算符調(diào)用工廠類初始化相應(yīng)運(yùn)算子類 oper.NumberA = Convert.ToDouble(strNumberA); oper.NumberB = Convert.ToDouble(strNumberB); strResult = oper.GetResult().ToString(); Console.WriteLine("結(jié)果是:" + strResult); Console.ReadLine(); } catch (Exception ex) { Console.WriteLine("您的輸入有錯(cuò):" + ex.Message); } }
二、工廠方法模式:
與簡(jiǎn)單工廠模式相比,增加了工廠類的虛類,并針對(duì)每一個(gè)運(yùn)算子類編寫(xiě)了一個(gè)工廠方法;當(dāng)增加運(yùn)算方式時(shí)只需增加運(yùn)算子類和工廠子類,不需對(duì)原有類進(jìn)行修改。運(yùn)算類代碼見(jiàn)上。
工廠方法模式實(shí)現(xiàn)時(shí),客戶端需要決定實(shí)例化哪一個(gè)工廠來(lái)實(shí)現(xiàn)運(yùn)算類,只是將簡(jiǎn)單工廠類的內(nèi)部邏輯判斷(switch)移到了客戶端代碼來(lái)進(jìn)行。
// 工廠類,接口,Creator interface IFactory { Operation CreateOperation(); }// 加法工廠,ConcreteCreator class AddFactory : IFactory { public Operation CreateOperation() { return new OperationAdd(); // 初始化加法類(ConcreteProduct)} } //減法工廠,ConcreteCreator class SubFactory : IFactory { public Operation CreateOperation() { return new OperationSub(); } } // 乘法工廠,ConcreteCreator class MulFactory : IFactory { public Operation CreateOperation() { return new OperationMul(); } } ///除法工廠,ConcreteCreator class DivFactory : IFactory { public Operation CreateOperation() { return new OperationDiv(); } }static void Main(string[] args) //客戶端調(diào)用 { IFactory operFactory = new AddFactory(); //初始化加法工廠 Operation oper = operFactory.CreateOperation(); //初始化加法類 oper.NumberA = 1; oper.NumberB = 2; double result=oper.GetResult(); Console.WriteLine(result); Console.Read(); }
三、抽象工廠模式
抽象工廠模式與工廠方法模式的區(qū)別是在于當(dāng)涉及到多個(gè)產(chǎn)品系列又是不同的分類時(shí),對(duì)專門的工廠模式的叫法而已。從圖上理解就是工廠方法模式解決的問(wèn)題只有一個(gè)A產(chǎn)品,而抽象工廠模式解決A、B、……甚至更多的產(chǎn)品。
優(yōu)點(diǎn):1.具體類只初始化一次,修改代碼時(shí)方便;2.讓具體的創(chuàng)建實(shí)例過(guò)程與客戶端分離,產(chǎn)品的具體類名被具體工廠的實(shí)現(xiàn)分離,不會(huì)出現(xiàn)在客戶代碼中。
增加產(chǎn)品時(shí)需增加AbstractProductC、ProductC1、ProductC2,修改AbstractFactory、ConcreteFactory1和ConcreteFactory2增加CreateProductC()方法。
//用戶表,用戶信息class User { private int _id; public int ID { get { return _id; } set { _id = value; } } private string _name; public string Name { get { return _name; } set { _name = value; } } }//部門表,部門信息class Department { private int _id; public int ID { get { return _id; } set { _id = value; } } private string _deptName; public string DeptName { get { return _deptName; } set { _deptName = value; } } }//用戶信息接口,AbstractProductA
interface IUser{ void Insert(User user); User GetUser(int id); }//SQL實(shí)現(xiàn)用戶信息操作,ProductA1class SqlserverUser : IUser{ public void Insert(User user) { Console.WriteLine("在Sqlserver中給User表增加一條記錄"); } public User GetUser(int id) { Console.WriteLine("在Sqlserver中根據(jù)ID得到User表一條記錄"); return null; }}//access實(shí)現(xiàn)用戶信息操作,ProductA2class AccessUser : IUser{ public void Insert(User user) { Console.WriteLine("在Access中給User表增加一條記錄"); } public User GetUser(int id) { Console.WriteLine("在Access中根據(jù)ID得到User表一條記錄"); return null; }}//部門信息接口,AbstractProductB
interface IDepartment { void Insert(Department department); Department GetDepartment(int id); }//SQL實(shí)現(xiàn)部門信息操作,ProductB1
class SqlserverDepartment : IDepartment { public void Insert(Department department) { Console.WriteLine("在Sqlserver中給Department表增加一條記錄"); } public Department GetDepartment(int id) { Console.WriteLine("在Sqlserver中根據(jù)ID得到Department表一條記錄"); return null; } }//ACCESS實(shí)現(xiàn)部門信息操作,ProductB2class AccessDepartment : IDepartment { public void Insert(Department department) { Console.WriteLine("在Access中給Department表增加一條記錄"); } public Department GetDepartment(int id) { Console.WriteLine("在Access中根據(jù)ID得到Department表一條記錄"); return null; } }//工廠接口,AbstractFactory
interface IFactory { IUser CreateUser(); IDepartment CreateDepartment(); }//SQL具體工廠類,ConcreteFactory1
class SqlServerFactory : IFactory { public IUser CreateUser() { return new SqlserverUser(); } public IDepartment CreateDepartment() { return new SqlserverDepartment(); } }//Accese具體工廠類,ConcreteFactory2
class AccessFactory : IFactory { public IUser CreateUser() { return new AccessUser(); } public IDepartment CreateDepartment() { return new AccessDepartment(); } }//客戶端調(diào)用static void Main(string[] args) { //初始化兩個(gè)產(chǎn)品 User user = new User(); Department dept = new Department(); //選擇實(shí)現(xiàn)哪個(gè)工廠 IFactory factory = new AccessFactory(); IUser iu = factory.CreateUser(); iu.Insert(user); iu.GetUser(1); IDepartment id = factory.CreateDepartment(); id.Insert(dept); id.GetDepartment(1); Console.Read(); } }
四、對(duì)抽象工廠模式的改進(jìn)
改進(jìn)手段:簡(jiǎn)單工廠+反射
第一步:取消AbstractFactory、ConcreteFactory1和ConcreteFactory2,用簡(jiǎn)單工廠類來(lái)實(shí)現(xiàn)。
//取消接口,只用一個(gè)類 class DataAccess { //指定用什么數(shù)據(jù)庫(kù) private static readonly string db = "Sqlserver"; //private static readonly string db = "Access"; //用戶信息維護(hù),根據(jù)指定判斷用哪個(gè)具體產(chǎn)品 public static IUser CreateUser() { IUser result = null; switch (db) { case "Sqlserver": result = new SqlserverUser(); break; case "Access": result = new AccessUser(); break; } return result; } //部門信息維護(hù),根據(jù)指定判斷用哪個(gè)具體產(chǎn)品 public static IDepartment CreateDepartment() { IDepartment result = null; switch (db) { case "Sqlserver": result = new SqlserverDepartment(); break; case "Access": result = new AccessDepartment(); break; } return result; } }//在客戶端程序中不用指定用哪個(gè)數(shù)據(jù)庫(kù),只需要操作即可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.CreateDepartment(); id.Insert(dept); id.GetDepartment(1); Console.Read(); }第二步,替換簡(jiǎn)單工廠中部分代碼,采用反射,可以將原執(zhí)行語(yǔ)句部分變成字符串形式易于變化。
//使用反射時(shí),必須引用using System.Reflection; //Assembly.Load(‘程序集名稱’).CreateInstance('命名空間.類名稱');class DataAccess { //指定程序集名稱,同時(shí)在配置文件中獲取‘DB’的值,在配置文件中指定數(shù)據(jù)庫(kù)類型 private static readonly string AssemblyName = "抽象工廠模式"; private static readonly string db = ConfigurationManager.AppSettings["DB"]; //指定類名稱,遵循命名規(guī)則 public static IUser CreateUser() { string className = AssemblyName + "." + db + "User"; return (IUser)Assembly.Load(AssemblyName).CreateInstance(className); } public static IDepartment CreateDepartment() { string className = AssemblyName + "." + db + "Department"; return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className); } }//配置文件中的寫(xiě)法<configuration> <appSettings> <add key="DB" value="Sqlserver"/> </appSettings></configuration>
PS:所有在用簡(jiǎn)單工廠的地方,都可以考慮用反射技術(shù)來(lái)去除switch或if,解除分支判斷帶來(lái)的耦合。
五、總結(jié)
工廠方法:定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定實(shí)例化哪一個(gè)類,工廠方法模式使一個(gè)類的實(shí)例化延遲到其子類;
抽象工廠:提供一個(gè)創(chuàng)建一系列或相關(guān)依賴對(duì)象的接口,而無(wú)需指定它們具體的類。
設(shè)計(jì)通常從工廠方法開(kāi)始,當(dāng)設(shè)計(jì)者發(fā)現(xiàn)需要更大的靈活性時(shí),設(shè)計(jì)便會(huì)向其他創(chuàng)建型模式演化;當(dāng)設(shè)計(jì)者在設(shè)計(jì)標(biāo)準(zhǔn)之間進(jìn)行權(quán)衡的時(shí)候,了解多個(gè)創(chuàng)建型模式可以給設(shè)計(jì)者更多的選擇余地。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注