C#设计模式之:抽象工厂模式与反射
抽象工廠模式【實例】:
定義一個用于創建對象的接口,讓子類決定實例化哪一個類
UML
?
代碼
class User
{
? ? private int _id;
? ? public int Id { get => _id; set => _id = value; }
? ? private string _name;
? ? public string Name { get => _name; set => _name = value; }
}
interface IUser
{
? ?void Insert(User user);
? ?User GetUser(int id);
}
class SqlserverUser : IUser
{
? ? public void Insert(User user)
? ? {
? ? ? ? Console.WriteLine("在SQL Server中給User表增加一條記錄");
? ? }
? ?public User GetUser(int id)
? ?{
? ? ? Console.WriteLine("在SQL Server中根據ID得到User表一條記錄");
? ? ? return null;
? ?}
}
class SqlServerFactory : IFactory
{
? ? public IUser CreateUser()
? ? {
? ? ? ? return new SqlserverUser();
? ? }
}
class AccessUser : IUser
{
? ? public User GetUser(int id)
? ?{
? ? ? ?Console.WriteLine("在Access中根據ID得到User表一條記錄");
? ? ? ?return null;
? ?}
? public void Insert(User user)
? ?{
? ? ? ?Console.WriteLine("在Access中給User表增加一條記錄");
? ?}
}
class AccessFactory : IFactory
{
? ? public IUser CreateUser()
? ?{
? ? ? ? return new AccessUser();
? ?}
}
// test
User user = new User();
//IFactory factory = new SqlServerFactory();
IFactory factory = new AccessFactory();
IUser iu = factory.CreateUser();
iu.Insert(user);
iu.GetUser(1);
// result
在Access中給User表增加一條記錄
在Access中根據ID得到User表一條記錄
抽象工廠模式(Abstract Factory)
提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類
UML
?
代碼
class Department
{
? ? ? private string name;
? ? ? private string id;
? ? ? public string Name { get => name; set => name = value; }
? ? ? public string Id { get => id; set => id = value; }
}
interface IDepartment
{
? ? ?void Insert(Department department);
? ? ?Department GetDepartment(int id);
}
class SqlserverDepartment : IDepartment
{
? ? public void Insert(Department department)
? ? {
? ? ? ? ?Console.WriteLine("在SQL Server中給Department表增加一條記錄");
? ? }
? ?public Department GetDepartment(int id)
? ?{
? ? ? ?Console.WriteLine("在SQL Server中根據ID得到Department表一條記錄");
? ? ? ?return null;
? ?}
}
class AccessDepartment : IDepartment
{
? ? public Department GetDepartment(int id)
? ?{
? ? ? ? Console.WriteLine("在Access中根據ID得到Department表一條記錄");
? ? ? ? return null;
? ?}
? ?public void Insert(Department department)
? ?{
? ? ? ? Console.WriteLine("在Access中給Department表增加一條記錄");
? ?}
}
class SqlServerFactory : IFactory
{
? ? public IUser CreateUser()
? ? ?{
? ? ? ? return new SqlserverUser();
? ? ?}
? ?public IDepartment CreateDepartment()
? ?{
? ? ? return new SqlserverDepartment();
? ?}
}
class AccessFactory : IFactory
{
? ?public IUser CreateUser()
? ?{
? ? ? ?return new AccessUser();
? ?}
? ?public IDepartment CreateDepartment()
? ?{
? ? ? ? return new AccessDepartment();
? ?}
}
// test
User user = new User();
Department dept = new Department();
//IFactory factory = new SqlServerFactory();
IFactory factory = new AccessFactory();
IUser iu = factory.CreateUser();
iu.Insert(user);
iu.GetUser(1);
IDepartment id = factory.CreateDepartment();
id.Insert(dept);
id.GetDepartment(1);
// result
在Access中給User表增加一條記錄
在Access中根據ID得到User表一條記錄
在Access中給Department表增加一條記錄
在Access中根據ID得到Department表一條記錄
IFactory 就是一個抽象工廠接口,它里面應該包含所有的產品創建的抽象方法
通常在運行時再創建一個ConcreteFactory類的實例,這個具體的工廠再創建具有特定實現的產品對象,也就是說為創建不同的產品對象,客戶商應使用不同的具體工廠
優點
便于交換系列產品,由于具體工廠類,在一個應用中只需要在初始化時出現一次,這使得改變一個應用的具體工廠變得很容易,它只要改變具體工廠即可使用不同的產品配置
它讓具體的創建實例過程與客戶端分離,客戶端是通過它們的抽象接口操縱實例,產品的具體類名也被具體的工廠實現分離,不會出現在客戶代碼中
缺陷
1,添加新的表,要更改多個工廠類
2,程序中有多個地方使用了
IFactory factory = new AccessFactory();
1
現在換個數據庫
IFactory factory = new SqlServerFactory();
1
你也要更改多個地方
總結:
簡單工廠模式:管理對象類 調用接口
抽象工廠模式:接口實現類 調用接口
用簡單工廠改進其缺陷
去除IFactory、SqlServerFactory和AccessFactory三個工廠類
使用DataAccess類取代它們
UML
?
代碼
class DataAccess
{
? ? private static readonly string db = "SqlServer";
? ? // private static readonly 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 CreateDepartment()
{
? ? ? IDepartment result = null;
? ? ? switch (db)
? ? ?{
? ? ? ? case "SqlServer":
? ? ? ? result = new SqlserverDepartment();
? ? ? ? break;
? ? ? ? case "Access":
? ? ? ? result = new AccessDepartment();
? ? ? ? break;
? ? ?}
? ? ? return result;
? ?}
}
// test
User user = new User();
IUser iu = DataAccess.CreateUser();
iu.Insert(user);
iu.GetUser(1);
Department dept = new Department();
IDepartment id = DataAccess.CreateDepartment();
id.Insert(dept);
id.GetDepartment(1);
// result
在SQL Server中給User表增加一條記錄
在SQL Server中根據ID得到User表一條記錄
在SQL Server中給Department表增加一條記錄
在SQL Server中根據ID得到Department表一條記錄
這里使用了簡單工廠的方法來解決了上面的缺陷,但同時又產生了新的問題(switch問題)
如果要新增Oracle數據庫,抽象工廠本來只要增加一個OracleFactory工廠即可,這里簡單工廠要修改switch增加case
.NET中的依賴注入( Dependency Injection)
using System.Reflection;
Assembly.Load("程序集名稱").CreateInstance("命名空間.類的名稱");
// 常規寫法
IUser result = new SqlServerUser();
// 反射寫法
using System.Reflection;
IUser result = (IUser)Assembly.Load("抽象工廠模式").CreateInstance("抽象工廠模式.SqlServerUser");
使用反射的具體代碼
using System.Reflection;
class DataAccess
{
? ? ?private static readonly string AssemblyName = "PatternTest";
? ? ?private static readonly string db = "AbstractPattern.Sqlserver";
? ? ?// private static readonly string db = "AbstractPattern.Access";
? ?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);
? }
}
上述代碼同樣得到了結果
如果我們增加了Oracle數據訪問,相關的類的增加是不可避免的,不過這叫擴展,開閉原則告訴我們對于擴展開放,對于修改關閉
我們只要修改db字符串變量的值為
// private static readonly string db = "AbstractPattern.Oracle";
1
每次更換數據庫時還是要修改程序修改db值重編譯,如果可以不修改程序,才是真正的開放-封閉原則
解決方案:使用配置文件
轉載于:https://www.cnblogs.com/lvjy-net/p/10430762.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的C#设计模式之:抽象工厂模式与反射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 6 有序集合ZSet(Sorted Se
- 下一篇: 其他基础知识