草庐IT

c# - 我怎样才能改进这个设计?

coder 2024-05-20 原文

让我们假设我们的系统可以执行操作,并且一个操作需要一些参数来完成它的工作。 我为所有操作定义了以下基类(为了您的阅读乐趣而进行了简化):

public abstract class BaseBusinessAction<TActionParameters> 
    : where TActionParameters : IActionParameters
{
    protected BaseBusinessAction(TActionParameters actionParameters)
    {
        if (actionParameters == null) 
            throw new ArgumentNullException("actionParameters"); 

        this.Parameters = actionParameters;

        if (!ParametersAreValid()) 
            throw new ArgumentException("Valid parameters must be supplied", "actionParameters");
    }

    protected TActionParameters Parameters { get; private set; }

    protected abstract bool ParametersAreValid();

    public void CommonMethod() { ... }
}

只是BaseBusinessAction的具体实现知道如何验证传递给它的参数是否有效,因此 ParametersAreValid是一个抽象函数。但是,我希望基类构造函数强制传递的参数始终有效,所以我添加了一个 调用 ParametersAreValid到构造函数,当函数返回 false 时我抛出异常.到目前为止一切顺利,对吧?好吧,不。 代码分析告诉我“not call overridable methods in constructors”这实际上很有意义,因为当调用基类的构造函数时 子类的构造函数尚未被调用,因此 ParametersAreValid方法可能无法访问某些关键成员变量 子类的构造函数将被设置。

所以问题是:我该如何改进这个设计?

我要添加 Func<bool, TActionParameters> 吗?基类构造函数的参数?如果我这样做了:

public class MyAction<MyParameters>
{
    public MyAction(MyParameters actionParameters, bool something) : base(actionParameters, ValidateIt)
    {
        this.something = something;
    }

    private bool something;

    public static bool ValidateIt()
    {
       return something;
    }

}

这会起作用,因为 ValidateIt是静态的,但我不知道...有没有更好的方法?

非常欢迎评论。

最佳答案

这是继承层次结构中常见的设计挑战——如何在构造函数中执行类相关行为。代码分析工具将此标记为问题的原因是此时派生类的构造函数尚未有机会运行,并且对虚方法的调用可能依赖于尚未初始化的状态。

所以你在这里有几个选择:

  1. 忽略这个问题。如果您认为实现者应该能够在不依赖类的任何运行时状态的情况下编写参数验证方法,那么请记录该假设并坚持您的设计。
  2. 将验证逻辑移到每个派生类构造函数中让基类只执行它必须执行的最基本、抽象类型的验证(空检查等)。
  3. 在每个派生类中复制逻辑。这种代码重复似乎令人不安,它为派生类打开了大门,忘记执行必要的设置或验证逻辑。
  4. 提供某种类型的 Initialize() 方法,该方法必须由消费者(或您的类型的工厂)调用,以确保在完全构建类型后执行此验证。这可能是不可取的,因为它要求实例化您的类的任何人都必须记住调用初始化方法——您认为构造函数可以执行该方法。通常,工厂可以帮助避免这个问题 - 它是唯一允许实例化您的类的工厂,并且会在将类型返回给消费者之前调用初始化逻辑。
  5. 如果验证不依赖于状态,则将验证器分解为一个单独的类型,您甚至可以将其作为通用类签名的一部分。然后您可以在构造函数中实例化验证器,将参数传递给它。每个派生类都可以定义一个带有默认构造函数的嵌套类,并将所有参数验证逻辑放在那里。下面提供了此模式的代码示例。

如果可能,让每个构造函数执行验证。但这并不总是可取的。在那种情况下,我个人更喜欢工厂模式,因为它使实现简单明了,而且它还提供了一个拦截点,以后可以在其中添加其他行为(日志记录、缓存等)。然而,有时工厂没有意义,在这种情况下,我会认真考虑创建独立验证器类型的第四种选择。

这是代码示例:

public interface IParamValidator<TParams> 
    where TParams : IActionParameters
{
    bool ValidateParameters( TParams parameters );
}

public abstract class BaseBusinessAction<TActionParameters,TParamValidator> 
    where TActionParameters : IActionParameters
    where TParamValidator : IParamValidator<TActionParameters>, new()
{
    protected BaseBusinessAction(TActionParameters actionParameters)
    {
        if (actionParameters == null) 
            throw new ArgumentNullException("actionParameters"); 

        // delegate detailed validation to the supplied IParamValidator
        var paramValidator = new TParamValidator();
        // you may want to implement the throw inside the Validator 
        // so additional detail can be added...
        if( !paramValidator.ValidateParameters( actionParameters ) )
            throw new ArgumentException("Valid parameters must be supplied", "actionParameters");

        this.Parameters = actionParameters;
    }
 }

public class MyAction : BaseBusinessAction<MyActionParams,MyActionValidator>
{
    // nested validator class
    private class MyActionValidator : IParamValidator<MyActionParams>
    {
        public MyActionValidator() {} // default constructor 
        // implement appropriate validation logic
        public bool ValidateParameters( MyActionParams params ) { return true; /*...*/ }
    }
}

关于c# - 我怎样才能改进这个设计?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2448920/

有关c# - 我怎样才能改进这个设计?的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  3. ruby-on-rails - 如果我将 ruby​​ 版本 2.5.1 与 rails 版本 2.3.18 一起使用会怎样? - 2

    如果我使用ruby​​版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby​​1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更

  4. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  5. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  6. 怎样用一台手机做自媒体? - 2

    其实做自媒体的成本并不高,入门只需要一部手机即可!在手机上找视频素材、使用手机剪辑视频、最后使用手机发布视频作品获得收益!方法并不难,今天这期内容就来给粉丝们分享一种小方法,每天稳定收益100-300,抓紧点赞收藏!1、找素材(1)使用手机拍摄自己喜欢的经典段落,使用程序把文案内容提取出来(2)也可以在豆瓣、知乎、微博等网站中找一些自己需要的文案素材(3)把文案进行润色修改,可以加入一些自己的观点(4)视频素材可以使用软件中自带的素材,也可以在素材网站中下载完整版的素材2、文案配音(1)把复制好的文案直接导入小程序中(2)调整音色、音调后一键合成音频即可(3)可以选择自己朗读配音,需要花一点时

  7. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  8. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  9. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  10. ruby-on-rails - 设计注册确认 - 2

    我在我的项目中有一个用户和一个管理员角色。我使用Devise创建了身份验证。在我的管理员角色中,我没有任何确认。在我的用户模型中,我有以下内容:devise:database_authenticatable,:confirmable,:recoverable,:rememberable,:trackable,:validatable,:timeoutable,:registerable#Setupaccessible(orprotected)attributesforyourmodelattr_accessible:email,:username,:prename,:surname,:

随机推荐