失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > C#设计模式之:抽象工厂模式与反射

C#设计模式之:抽象工厂模式与反射

时间:2020-08-22 02:54:45

相关推荐

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值重编译,如果可以不修改程序,才是真正的开放-封闭原则

解决方案:使用配置文件

如果觉得《C#设计模式之:抽象工厂模式与反射》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。