C#之三十九 抽象工厂模式

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
简介: C#之三十九 抽象工厂模式

     在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时由于需求的变化,往往存在着更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象的创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?这就是我们要说的抽象工厂模式。


视频课 C#高级程序设计


重点:


Ø      抽象工厂模式概念


Ø      抽象工厂模式的模型图


Ø      抽象工厂模式访问多种数据库


预习功课:


Ø      什么是抽象工厂模式


Ø       如何使用抽象工厂模式访问多种数据库


5.1 抽象工厂模式概述


    抽象工厂是一种创建型模式,是为了解决实例化时所带来的问题。这种模式的意图是:提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定他们的具体类。


5.1.1 如何不换数据库


   假如某公司已经做好了一个企业的电子商务网站,用Sql Server作为数据库;目前又接到类似于该企业需求的项目,但该公司为了省钱,想用Access,那将如何呢?


   Sql Server和Access在Ado.Net上的使用是不同的,在Sql Server上用的是System.Data.SqlClient命名空间下的SqlConnection、SqlCommand、SqlParameter、SqlDataReader、SqlDataAdapter,而Access则要用System.Data.OleDb命名空间下的相应对象。


   另外,二者在Sql语法上也有很多的不同,比如在插入数据时,Access必须要insert into而Sql Server可以不用into;SqlServer中的GetDate()在Access中没有,需要改写成Now();Sql Server中有字符串函数Substring,而Access根本不能用。另外,对于Access中的关键字要用“[]”括起来,否则报错。


   因此,如果有多个同类型的项目,而数据库不同,修改代码的工作量也是空前的,那么有没有一种好的办法,使我们可以根据不同的数据库来执行不同的操作呢?


5.1.2 使用抽象工厂模式的数据访问程序



“AbstractProductA和AbstractProductB是两个抽象产品,之所以为抽象,是因为它们都有可能有两种不同的实现,而ProductA1、ProductA2和ProductB1、ProductB2就是对两个抽象产品的具体分类的实现,比如ProductA1可以理解为SqlserverUser,而ProductB1是AccessUser。”


   “这么说,Ifactory是一个抽象工厂接口,它里面应该包含所有的产品创建的抽象方法。而ConcreateFactory1和ConcreateFactory2就是具体的工厂了。就像SqlserverFactory和AccessFactory一样。通常是在运行时再创建一个ConcreateFactory类的实例,这个具体的工厂再创建具有特定实现的产品对象,也就是说,为创建不同的产品对象,客户端应使用不同的具体工厂。”


 


5.1.3 抽象工厂模式的优点与缺点


抽象工厂模式的优点:


一.易于交换产品系列,由于具体工厂类,例如Ifactoryfactory=new AccessFactory(),在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。


我们的设计不能去防止需求的更改,那么我们的理想便是让改动变得最小,现在如果你要更改数据库访问,我们只需要更改具体工厂就可以做到。


   二.它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。


5.1.4 用反射+抽象工厂的数据访问程序


   如果我们现在程序再增加对Oracle的访问,不仅仅需要在抽象工厂中增加一个OracleFactory工厂类,另外还需要在数据访问类的方法的switch方法中增加case。


   这个时候,我们就可以依据字符串db的值去实例化相应的数据库类。就需要用到反射技术了。


   使用反射技术,首先需要引用System.Reflection命名空间,使用反射的写法如下:


   using System.Reflection;  


 


   Iuser  result =(IUser)Assembly.Load("抽 象 工 厂 模 式").CreateInstance;


   现在,我们就可以将程序由编译时转为运行时,由于“CreateInstance(抽象工厂模式.SqlserverUser”)’中的字符串是可以写成变量的,而变量的值到底是Sql Server,还是Access完全可以由事先的那个db变量决定。 修改过后的数据访问类,用反射技术来实现,取代Ifactory、SqlserverFactory和AccessFactory。代码如下:      

using System.Reflection;   
    class DataAccess
    {
       private static readonly string AssemblyName="抽象工厂模式";
       private static readonly string db="Sqlserver";
      public static IUser CreateUser()
    {
       string className=AssemblyName+"."+db+"User";
       return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
}
public static Idepartment   CreateDepartment()
{
    string className=AssemblyName+"."+"Department";
    return (Ideparment)Assembly.Load(AssemblyName).CreateInstance(className);
}  
}

现在如果我们增加了Oracle数据库访问,相关类的增加是不可避免的,这点无论用任何方法都解决不了,不过这叫扩展,开放-封闭原则性告诉我们,对于扩展,我们开放。但对于修改,我们应该尽量关闭。针对现状,我们需要更改“private static readonly string db="Sqlserver"”为“private static readonly string db="Oracle"”,即(IUser)Assembly.Load(AssemblyName).CreateInstance(className)语句发生了变化。


这样,DataAccess.CreateUser()本来得到的是SqlserverUser的实例,现在就变成了OracleUser的实例了。


如果需要增加FoodInfo时,则再增加与该FoodInfo相关三个类,再修改


DataAccess,在其中增加一个publicstatic Iproject CreateFoodInfo()方法即可。但是,如果更改数据库,还得去修改程序(修改db的值)并重新编译,是否有更好的方法来解决此问题呢?


5.1.5 用反射+配置文件实现数据访问程序


针对上节的问题,我们可以利用配置文件来解决。添加的App.config文件代码如下:  

 <?xml version="1.0" encoding="utf-8"?>
<configuration>
    <appSettings>
       <add key="DB" value="Sqlserver"/>
    </appSettins>
</configuration>


在项目上“右键”,手动添加引用System.configuration,并在程序开头增加usingSystem.Configuration,然后更改DataAccess类的字段。


private staticreadonly string db=ConfigurationManager.AppSettings["DB"];


到目前为止,我们应用了反射+抽象工厂模式解决了数据库访问的可维护、可扩展的问题。


相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
3月前
|
设计模式 C#
C# 一分钟浅谈:工厂模式与抽象工厂模式
【10月更文挑战第10天】本文介绍了面向对象编程中的两种常见创建型设计模式:工厂模式和抽象工厂模式。工厂模式通过共同接口创建对象,隐藏创建逻辑,提高封装性和扩展性;抽象工厂模式则提供了一系列相关对象的创建接口,适用于多个相关产品族的创建。文章通过C#代码示例详细解释了这两种模式的实现和应用场景,并讨论了它们的优点、缺点及常见问题。
67 19
|
SQL C# 数据库
C#设计模式之三抽象工厂模式(AbstractFactory)【创建型】
原文:C#设计模式之三抽象工厂模式(AbstractFactory)【创建型】 一、引言     写了3篇有关设计模式的文章了,大家有了些反馈,说能从中学到一些东西,我感到很欣慰,那就继续努力。今天我要写第四个模式了,该模式叫抽象工厂。
1221 0
|
SQL C# uml
C# 设计模式----抽象工厂模式
原文地址:C#设计模式(4)——抽象工厂模式 一、引言 在上一专题中介绍了工厂方法模式,工厂方法模式是为了克服简单工厂模式的缺点而设计出来的,简单工厂模式的工厂类随着产品类的增加需要增加额外的代码),而工厂方法模式每个具体工厂类只完成单个实例的创建,所以它具有很好的可扩展性。但是在现实生活中,一个工厂只创建单个产品这样的例子很少,因为现在的工厂都多元化了,一个工厂创建一系列的产品,如果我们
1220 0
|
XML SQL C#
乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern)
原文:乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern) 作者:webabcd 介绍 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
967 0
|
SQL C#
C#设计模式(4)——抽象工厂模式
原文:C#设计模式(4)——抽象工厂模式 一、引言 在上一专题中介绍了工厂方法模式,工厂方法模式是为了克服简单工厂模式的缺点而设计出来的,简单工厂模式的工厂类随着产品类的增加需要增加额外的代码),而工厂方法模式每个具体工厂类只完成单个实例的创建,所以它具有很好的可扩展性。
872 0
|
2月前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
43 3
|
15天前
|
存储 安全 编译器
学懂C#编程:属性(Property)的概念定义及使用详解
通过深入理解和使用C#的属性,可以编写更清晰、简洁和高效的代码,为开发高质量的应用程序奠定基础。
62 12
|
2月前
|
设计模式 C# 图形学
Unity 游戏引擎 C# 编程:一分钟浅谈
本文介绍了在 Unity 游戏开发中使用 C# 的基础知识和常见问题。从 `MonoBehavior` 类的基础用法,到变量和属性的管理,再到空引用异常、资源管理和性能优化等常见问题的解决方法。文章还探讨了单例模式、事件系统和数据持久化等高级话题,旨在帮助开发者避免常见错误,提升游戏开发效率。
73 4