如何在类后面隐藏逻辑以提高方法的可读性并重构类以遵循SRP?

ILo*_*low 9 .net c# refactoring single-responsibility-principle

我有一种算法可以为实体创建一个版本,然后将其保存在下面的2个实体中:

1)变体

2)类别

interface IEntityVersion
{
    string GetVersion();
}

public class EntityVersion : IEntityVersion
{
    public string GetVersion()
    {
        return null;
    }
}

public interface IVariant
{
    void Process(Variant model, string connectionString);
}

public abstract class BaseVariant : IVariant
{
    private readonly IEntityVersion _entityVersion = new EntityVersion();

    public void Process(Variant model, string connectionString)
    {
        try
        {
            Transform();
            string variantVersion = _entityVersion.GetVersion();
            using (var myConnection = new SqlConnection(connectionString))
            {
                myConnection.Open();
                using (var transaction = myConnection.BeginTransaction())
                {
                    try
                    {
                        VariantRepo.UpdateVariantVersion(
                          myConnection,
                          transaction, model.VariantId, variantVersion);

                        CategoryRepo.UpdateCategoryVariantMapping(
                                     myConnection,
                                     transaction, model.CategoryId, variantVersion);

                        transaction.Commit();
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                        DeleteStep1Data();
                    }
                }
            }
        }
        catch (Exception)
        {
            //log error
        }
    }

    protected abstract void DeleteStep1Data();
    protected abstract void Transform();
}

public class Variant
{
    public int VariantId { get; set; }
    public int CategoryId { get; set; }
}

public class VariantRepo
{
    public static void UpdateVariantVersion(SqlConnection sqlConnection,
        SqlTransaction transaction, int variantId, string version)
    {
        //save logic here
    }
}

public class CategoryRepo
{
    public static void UpdateCategoryVariantMapping(SqlConnection sqlConnection,
        SqlTransaction transaction, int categoryId, string version)
    {
        //save logic here
    }
}
Run Code Online (Sandbox Code Playgroud)

我有2个派生类型(AggregateCalculatorAdditionCalculator),每个都有自己的实现TransformDeleteStep1Data方法。

public class AggregateCalculator : BaseVariant
{
    protected override void DeleteStep1Data() // Is it violating SRP ?
    {
        throw new NotImplementedException();
    }

    protected override void Transform()
    {
        throw new NotImplementedException();
    }
}

public class AdditionCalculator : BaseVariant
{
    protected override void DeleteStep1Data()// Is it violating SRP ?
    {
        throw new NotImplementedException();
    }

    protected override void Transform()
    {
        throw new NotImplementedException();
    }
}
Run Code Online (Sandbox Code Playgroud)

我觉得该Process方法工作量很大,并且是否有可能将与版本保存相关的逻辑隐藏在EntityVersion类后面,以使该Process方法看起来很简单。

Step1并且Step2处于同步状态,以便如果发生错误Step2,我调用该DeleteStep1Data方法删除保存在中的所有数据Step1

我也感觉像我的2个派生类,AggregateCalculator并且AdditionCalculator正在处理1个以上的职责,即运行转换并删除转换过程中存储的数据,尽管我不确定这是否成立。

是否可以重构上述代码以提高可读性和处理SRP?

Hoo*_*ini 5

试图了解你的问题

您有一个实体...当实体更改时,您想为您的实体创建一个更改版本。我不清楚的是,为什么需要同时针对变体和类别跟踪此更改?

假设您的实体为,car并且该实体的类别为ToyotaBMWNissan。现在您的实体,假设“ id = 123的丰田电晕”已更改。为什么需要根据类别跟踪更改?您不能只说id = 123的实体已更改吗?

违反SRP

正如我在评论中提到的那样,由于您遗漏了部分逻辑,因此很难理解您的代码是否违反了SRP,但是我可以给您一些一般性的建议:

您有一个名为的类AggregateCalculator,我假设此类的主要职责是计算Transform()方法中发生的聚合。现在您需要执行2个步骤Transform()。这不一定违反SRP ...,因为从更高层次上讲,您的聚合计算器会做一件事:计算聚合。

您可以查找违反SRP的一般迹象:

  1. 根据Nikola Malovic的IoC第二定律

    任何具有超过3个依赖项的类都应被质疑违反SRP

  2. 如果您的班级规模太大,那么您需要向其询问是否违反SRP。

违反DRY

您的两个类:AggregateCalculatorAdditionCalculator分两步进行计算,分别是步骤1步骤2 ...,并且您有一个通用的方法:如果步骤2失败,则DeleteStep1Data()在两个类中都删除步骤1 ...我假设实现每个类的都不同,但是我觉得它仍然包含重复的代码(不是DRY)。有人可能会说这也违反了SRP,因为它同时负责:计算聚合和“镜像数据库事务”(很难看到完整的代码,这很难分辨)。DeleteStep1Data()AggregateCalculator

看来步骤1步骤2都是数据库事务,因此另一种方法是将两个步骤都放在一个数据库事务中……例如,您可以编写如下存储过程:

CREATE PROCEDURE AggregateCalculationSP
AS
BEGIN
    BEGIN TRANSACTION t1
        BEGIN TRY
            -- do step 1
            -- do step 2
        END TRY
        BEGIN CATCH
            ROLLBACK TRANSACTION t1
        END CATCH
    COMMIT TRANSATION t1
END
Run Code Online (Sandbox Code Playgroud)

现在,您可以DeleteStep1Data()从课堂上上课。

  • 如果您无法解释问题,那么在这里很难获得好的建议。您能否解释为什么不选择使用SP? (3认同)