我们在《SqlSugar开发框架》中,有时候都会根据一些需要引入一些设计模式,主要的目的是为了解决问题提供便利和代码重用等目的。而不是为用而用,我们的目的是解决问题,并在一定的场景下以水到渠成的方式处理。不过引入任何的设计模式,都会增加一定的学习难度,除非是自己本身领会比较好了,就会显得轻松一些。本篇随笔抽取一些应用场景来介绍相关设计模式,有些地方如列举有一定的偏颇之处,还请告知以便斧正。

1、Winform的本地访问和基于Web API的访问方式

Winform中的界面展示,以及数据处理,都需要具体实现的支撑,由于本身IOC控制反转的接口设计,我们对具体数据的访问,也是基于特定的接口层进行调用的,具体的实现,则是在程序启动的时候,注入对应的接口实现即可。

以上的业务接口层和数据处理层分开,数据处理层会根据配置信息采用不同的数据库实现方式,如可能是基于SQLServer、Oracle、Mysql、SQLite、PostgreSQL等不同的数据库,这种方式是软件开发中常见的一种原则——接口与实现分离的原则,也称为接口隔离原则(Interface Segregation Principle,ISP)。

接口隔离原则是面向对象设计中的一项原则,它主张一个类不应该强迫其用户依赖于它们不需要的方法。简单来说,就是应该将一个接口拆分为多个较小的接口,这样客户端只需要知道与其相关的接口即可,而不需要了解其他接口的细节。

接口与实现分离的设计模式有很多,常见的包括:

  1. 工厂模式(Factory Pattern):工厂模式通过定义一个创建对象的接口,但是让子类决定实例化哪个类。这样,一个类的实例化延迟到其子类。

  2. 抽象工厂模式(Abstract Factory Pattern):抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

  3. 适配器模式(Adapter Pattern):适配器模式允许将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。

  4. 代理模式(Proxy Pattern):代理模式为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用。

在我们有些情况下,不是直接访问具体的本地数据库,有可能是间接调用Web API的接口服务的,而我们使用的时候,为了方便,可能需要进行一定的封装处理,如下图示。

如果我们这里增加一个对Web API的调用,那么在这里注册的时候,切换向Web API代理的注册接口就可以,如下图所示。

因此原来的Winform界面上的调用代码,不需要任何变化,只需要注入不同的接口实现,就能获得不同的方式:普通访问数据库方式,还是分布式获取服务WebAPI的处理方式。

通过切换开关变量的方式,客户可以非常方便的自由切换不同的数据访问方式。数据提供服务,可以是直接访问数据库的方式,也可以是远端的Web API服务方式,从而实现更加广泛的业务需求。

2、基于接口和基类的继承方式简化重复代码

基于接口和基类的继承方式不是特定的设计模式,而是一种面向对象设计的基本原则和实践。

这种方式通常用于实现多态性(Polymorphism)、抽象化(Abstraction)和代码重用。在面向对象的编程语言中,通过定义接口(Interface)和基类(Base Class),可以实现一种规范化的编程模式,让代码更加灵活、可扩展和易于维护。

这种方式的优点包括:

  1. 多态性: 通过接口和基类,不同的子类可以实现相同的接口或继承相同的基类,从而可以以统一的方式对待不同的对象。

  2. 代码重用: 可以将通用的功能和行为定义在接口或基类中,从而使得子类可以重用这些功能和行为,减少重复代码的编写。

  3. 解耦和模块化: 接口和基类可以帮助解耦不同模块之间的依赖关系,提高代码的模块化程度,使得系统更易于理解和维护。

虽然基于接口和基类的继承方式不是一个独立的设计模式,但它是很多设计模式的基础,比如工厂模式、策略模式、模板方法模式等都会使用到接口和基类的继承方式。

在随笔《基于SqlSugar的开发框架循序渐进介绍(5)-- 在服务层使用接口注入方式实现IOC控制反转》我们介绍过具体实现类的继承关系,一般都是构建相应的基类和接口,然后才是具体的业务实现和接口,这样处理可以重用基类的很多接口,提高代码的重用效率。

而对应Web API的代理调用类,那么为了极大的重用常规的接口处理,我们需要类似的继承关系。

而在Web API的服务端中,我们为了重用,也是以基类和接口的方式来统一处理相关的逻辑。如我们根据项目的需要,定义了一些Web API控制器的基类,用于实现不同的功能。

同样,BS的前端和移动端,我们根据框架后端的接口进行前端JS端的类的封装处理,引入了ES6类的概念实现业务基类接口的统一封装,简化代码。

权限模块我们涉及到的用户管理、机构管理、角色管理、菜单管理、功能管理、操作日志、登录日志等业务类,那么这些类继承BaseApi,就会具有相关的接口了,如下所示继承关系。

按照这个思路,我们在BaseApi的ES6类里面定义了对应Web API基类里面的操作方法,如下所示。

这样,我们在创建一个业务类的时候,如果没有特殊的自定义接口,只需要继承基类BaseApi即可具有所有的常规基类方法了。

3、简单工厂设计模式

简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它提供了一个统一的接口来实例化一组相关或相似的对象,而无需暴露对象的创建逻辑给客户端。

简单工厂模式包含以下几个角色:

  1. 工厂(Factory): 负责创建具体产品的类。它通常包含一个或多个静态方法,根据客户端的参数来决定创建并返回哪种具体产品的实例。

  2. 产品接口(Product Interface): 声明了具体产品类的共同接口,客户端通过这个接口与具体产品类进行交互。

  3. 具体产品(Concrete Products): 实现了产品接口的具体类,是工厂创建的目标对象。

简单工厂模式的核心思想是将对象的创建和使用进行分离,客户端只需要知道使用工厂提供的接口来获取所需的产品,而无需了解产品是如何被创建的。这样的设计使得系统更加灵活,可以随时更改具体产品的创建方式而不影响客户端的代码。

在基于《SqlSugar开发框架》中,我们设计了一些系统服务层的基类,在基类中会有很多涉及到相关的数据处理操作的,如果需要跟踪具体是那个用户进行操作的,那么就需要获得当前用户的身份信息,包括在Web API的控制器中也是一样,需要获得对应的用户身份信息,才能进行相关的身份鉴别和处理操作。

为了方便获取用户身份的信息,我们定义一个接口 IApiUserSession 如下所示。

/// <summary>
/// API接口授权获取的用户身份信息-接口
/// </summary>
public interface IApiUserSession
{
/// <summary>
/// 用户登录来源渠道,0为网站,1为微信,2为安卓APP,3为苹果APP
/// </summary>
string Channel { get; } /// <summary>
/// 用户ID
/// </summary>
int? Id { get; } /// <summary>
/// 用户名称
/// </summary>
string Name { get; } /// <summary>
/// 用户邮箱(可选)
/// </summary>
string Email { get; } /// <summary>
/// 用户手机(可选)
/// </summary>
string Mobile { get; } /// <summary>
/// 用户全名称(可选)
/// </summary>
string FullName { get; } /// <summary>
/// 性别(可选)
/// </summary>
string Gender { get; } /// <summary>
/// 所属公司ID(可选)
/// </summary>
string Company_ID { get; } /// <summary>
/// 所属公司名称(可选)
/// </summary>
string CompanyName { get; } /// <summary>
/// 所属部门ID(可选)
/// </summary>
string Dept_ID { get; } /// <summary>
/// 所属部门名称(可选)
/// </summary>
string DeptName { get; } /// <summary>
/// 把用户信息设置到缓存中去
/// </summary>
/// <param name="info">用户登陆信息</param>
/// <param name="channel">默认为空,用户登录来源渠道:0为网站,1为微信,2为安卓APP,3为苹果APP </param>
void SetInfo(LoginUserInfo info, string channel = null);
}

IApiUserSession的一个空白接口定义,它需要依赖于具体的接口实现,我们具体会使用基于Principal或者缓存方式实现记录用户身份的信息实现,如下是它们的类关系。

在客户端和Web API的交换信息过程中,通过JWT的令牌方式,可以携带一些相关的用户身份信息。

在登录授权的这个时候,控制器会把相关的Claim信息写入到token中的,我们在客户端发起对控制器方法的调用的时候,这些身份信息会转换成对象信息。

在监视窗口中查看IApiUserSession对象,可以查看到对应的信息。

简单工厂的设计模式,是比较经常用到的一种设计模式,如我在随笔《基于SqlSugar的开发框架循序渐进介绍(26)-- 实现本地上传、FTP上传、阿里云OSS上传三者合一处理》中介绍到,根据配置信息来确定上传的处理路径选择,就是一种简单的工厂设计模式。

文件上传处理应该由程序进行配置,决定使用那种方式,那么这里面我们为了弹性化处理, 在文件上传模块中采用选项模式【Options】处理常规上传和FTP文件上传的配置参数信息。

微软引入选项模式,它是用于配置框架服务使用的设置. 选项模式由Microsoft.Extensions.OptionsNuGet包实现,除了ASP.NET Core应用,它还适用于任何类型的应用程序,如果需要了解,微软的文档详细解释了选项模式。

选项模式的限制之一是你只能解析(注入) IOptions <MyOptions> 并在依赖注入配置完成(即所有模块的ConfigureServices方法完成)后获取选项值。如果你正在开发一个模块,可能需要让开发者能够设置一些选项,并在依赖注入注册阶段使用这些选项. 你可能需要根据选项值配置其他服务或更改依赖注入的注册代码。IOptions<>是单例,因此一旦生成了,除非通过代码的方式更改,它的值是不会更新的。

在本地文件处理过程中,如果是Web API方式调用服务层,那么就在Web API所在的文件系统中,如果是Winform界面直接调用服务层,那么就是在当前系统中处理文件,这种方式可以有效的管理我们的文件信息。

在FTP文件处理过程中,则是根据选项参数的信息,调用FluentFTP类库进行文件的上传操作。

在OSS对象存储处理过程中,我们一般基于阿里云、腾讯云等这些云服务OSS的处理方式,一般它们会提供相应开发语言的SDK,我们引用并进行整合即可。

对于阿里云的OSS来说,对应的AccesKey和SecretKey自己可以通过查看账户的信息可以获取到。

以上就是一些场景的应用设计模式,当前开发框架里面,有很多其他的场景也同样会引入一些不同的处理方法,不过主旨都是希望采用较小的代价和难度,来解决复杂的问题的思路。

链接附注:

如对我们的代码生成工具有兴趣,可以到官网下载使用《代码生成工具Database2Sharp》。

如需了解我们官网对《SqlSugar开发框架》的介绍,可以参考《SqlSugar开发框架》了解。

如需阅读我们对于《SqlSugar开发框架》文章介绍,可以参考博客园的随笔标签《SqlSugar随笔 , WPF随笔》学习了解。

我们在SqlSugar开发框架中,用到的一些设计模式的更多相关文章

  1. PostgreSQL介绍以及如何开发框架中使用PostgreSQL数据库

    最近准备下PostgreSQL数据库开发的相关知识,本文把总结的PPT内容通过博客记录分享,本随笔的主要内容是介绍PostgreSQL数据库的基础信息,以及如何在我们的开发框架中使用PostgreSQ ...

  2. Winform开发框架中实现同时兼容多种数据库类型处理

    在很多应用系统里面,虽然一般采用一种数据库运行,但是由于各种情况的需要,可能业务系统会部署在不同类型的数据库上,如果开发的系统能够很方便支持多种数据库的切换,那可以为我们减少很多烦恼,同时提高系统的适 ...

  3. 在Winform开发框架中,利用DevExpress控件实现数据的快速录入和选择

    在实际的项目开发过程中,有好的控件或者功能模块,我都是想办法尽可能集成到我的WInform开发框架中,这样后面开发项目起来,就可以节省很多研究时间,并能重复使用,非常高效方便.在我很早之前的一篇博客& ...

  4. Winform开发框架中工作流模块之申请单草稿处理

    在我们开发工作流模块的时候,有时候填写申请单过程中,暂时不想提交审批,那么可以暂存为草稿,以供下次继续填写或者提交处理,那么这个草稿的功能是比较实用的,否则对于一些填写内容比较多的申请单,每次要重填写 ...

  5. 参照企业微信审批业务,在Winform开发框架中工作流模块的实现业务审批

    目前微信的企业号已经切换到企业微信里面,这个是一个APP程序,提供了很丰富的企业应用,其中包括了业务审批处理,审批业务包括请假.报销.费用.出差等很多个审批场景,在Winform开发框架中工作流模块这 ...

  6. Winform开发框架中工作流模块之审批会签操作(2)

    前面随笔介绍了请假申请单和报销申请单两个不同的业务表单的流程处理,一个是单表信息,一个包含明细的主从表信息,后者包含了条件流程的处理,在流程审批中,一般还有一种流程处理就是会签的操作,会签处理是几个审 ...

  7. Winform开发框架中工作流模块之审批会签操作

    在前面介绍了框架中工作流的几个开发过程,本篇随笔重点介绍一下日常审批环节中的具体处理过程,从开始创建表单,以及各个审批.会签过程的流转过程,希望大家对其中流程的处理有一个大概的印象. 1.请假申请表单 ...

  8. Winform开发框架中工作流模块的业务表单开发

    在我们开发工作流的时候,往往需要设计到具体业务表单信息的编辑,有些是采用动态编辑的,有些则是在开发过程中处理的,各有各的优点,动态编辑的则方便维护各种各样的表单,但是数据的绑定及处理则比较麻烦,而自定 ...

  9. Winform开发框架中工作流模块的表设计分析

    在较早博客随笔里面写过文章<Winform开发框架之简易工作流设计>之后,很久没有对工作流部分进行详细的介绍了,本篇继续这个主题,详细介绍其中的设计.实现及效果给大家,这个工作流在好几年前 ...

  10. 在Bootstrap开发框架中使用Grid++报表

    之前在随笔<在Winform开发中使用Grid++报表>介绍了在Winform环境中使用Grid++报表控件,本篇随笔介绍在Bootstrap开发框架中使用Grid++报表,也就是Web环 ...

随机推荐

  1. Go-值传递&引用传递

    值类型和引用类型 值类型关注其值 引用类型关注其指针 值类型和引用类型区别在于传递值的时候拷贝的对象不同,值传递拷贝是变量的值,引用传递拷贝的是变量的指针 拷贝 -- 传递值 赋值 函数调用 初始化 ...

  2. [转帖]SMEMBERS:获取集合包含的所有元素

    https://www.bookstack.cn/read/redisguide/spilt.4.291fab46a3b4f05c.md SMEMBERS set 以下代码展示了如何使用 SMEMBE ...

  3. Grafana针对内存监控值的学习与使用

    Grafana针对内存监控值的学习与使用 背景 因为学习内存相关的知识, 可以通过pgcacher/sar -r 等命令监控系统信息. 但是现在发现. 不太直观, 所以想着使用别的方式来进行处理. 然 ...

  4. [转帖]Linux中查看各文件夹大小命令du -h --max-depth=1

    https://www.cnblogs.com/the-tops/p/8798678.html 最近排查服务器异常的时候,常会遇到磁盘慢的情况,这个时候,查找那个文件夹占用的内存的时候常用到这个命令: ...

  5. [转帖]Kafka 核心技术与实战学习笔记(七)kafka集群参数配置(上)

    一.Broker 端参数 Broke存储信息配置 log.dirs:非常重要,指定Broker需要使用的若干文件目录路径,没有默认值必须亲自指定. log.dir:他只能表示单个路径,补充上一个参数用 ...

  6. [转帖]如何在本地编译安装部署自动化回归测试平台 AREX

    https://zhuanlan.zhihu.com/p/613877597 AREX 官方 QQ 交流群:656108079 本文将详细为大家介绍一下自动化回归测试平台 AREX 以及如何在本地进行 ...

  7. [转帖]【k8s】1、基础概念和架构及组件

    文章目录 一.kubernetes概述 1.什么是kubernetes? 2.应用程序部署方式的演变 3.为什么要用kubernetes? 二.kubernetes 特性 三.Kubernetes集群 ...

  8. Win10 查看无线局域网的密码

    1. 打开命令行 输入 control 打开控制面板 2. 进入网络和共享中心 3. 打开连接 4. 使用如下进行查看.

  9. Rsync的简单使用

    Rsync的简单使用 需求 一个运行很久的系统里面可能包含了非常多的垃圾文件. 但是又不可能随便删除, 很多垃圾可能有某些奇葩的用法. 有时候新建一个应用复制文件的话比较浪费磁盘和带宽. 所以这里简单 ...

  10. Arthas 超简单离线使用教程

    简介 Arthas 是阿里巴巴开源的一套监控java应用的工具 官网的文档地址: https://arthas.aliyun.com/doc/ 官方的简介说明: Arthas 是Alibaba开源的J ...