【问题标题】:Mastering dto polimorphism掌握数据多态性
【发布时间】:2016-01-21 12:12:51
【问题描述】:

我提到我与 DTO 的合作不多。我在 DataTransfereObjects 上玩弄多态主义。我想不出一个好的解决方案,所以我制作了这个代码示例来掌握多态与 DataTransfereObjects 和不同的逻辑实现,使用多态、泛型、接口、抽象等。

请检查代码。提示我有什么不好,可以做得更好或更容易。检查accessmodifier,还要检查SOLID(认为我没有正确理解它)。最后好像太复杂了,这样解决是不是很常见?

实际上,我尝试调用一些(反)序列化程序逻辑,它使用 baseDto 来获取派生的 dto,而不会丢失它们的特定信息。该代码应该是解决此类问题的干净抽象沙箱。

void Main()
{
    var twoIngrDto = new TwoIngredientsDto();
    var threeIngrDto = new ThreeIngredientsDto(); 

    var twoIngrMulAnswerChecker = new TwoIngredientsMultiplicationAnswerChecker();
    var threeIngrAddAnswerChecker = new ThreeIngredientsAdditionAnswerChecker();

    twoIngrMulAnswerChecker.IsTheAnswerCheckImplementationTheAnswer(twoIngrDto); //TRUE .Dump();
    threeIngrAddAnswerChecker.IsTheAnswerCheckImplementationTheAnswer(threeIngrDto); //TRUE .Dump();
    twoIngrMulAnswerChecker.IsTheAnswerCheckImplementationTheAnswer(threeIngrDto); //FALSE .Dump();

    IAnswerCheck answerchecker = new IngredientsAnswerChecker();
    answerchecker.CheckAnswer(twoIngrMulAnswerChecker, twoIngrDto); //TRUE .Dump();
    answerchecker.CheckAnswer(threeIngrAddAnswerChecker, threeIngrDto); //TRUE .Dump();

    /// QUESTION: How can I use the answerchecker 'twoIngrMulAnswerChecker' with the derived DTO 'threeIngrDto'
    /// It failes with following error:
    /// The type 'UserQuery.TwoIngredientsMultiplicationAnswerChecker' cannot be used as 
    /// type parameter 'T' in the generic type or method 'UserQuery.IngredientsAnswerChecker.CheckAnswer<T,DTO>(T, DTO)'. 
    /// There is no implicit reference conversion from 'UserQuery.TwoIngredientsMultiplicationAnswerChecker' 
    /// to 'UserQuery.TheAnswerChecker<UserQuery.ThreeIngredientsDto>'.
    //answerchecker.CheckAnswer(twoIngrMulAnswerChecker, threeIngrDto).Dump();
    answerchecker.CheckAnswer(twoIngrMulAnswerChecker, (TwoIngredientsDto)threeIngrDto).Dump(); // is casting the solution? 
}

interface IAnswerCheck
{
    bool CheckAnswer<T, DTO>(T answerCkecker, DTO ingredientsDto) 
        where T : TheAnswerChecker<DTO>
        where DTO : IngredientDto;
}

public abstract class TheAnswerChecker<T> where T : IngredientDto
{
    internal abstract int TheAnswerCheckImplementation(T answerIngredietsDto);
    private int TheAnswer {get { return 42;} }

    public bool IsTheAnswerCheckImplementationTheAnswer(T answerIngredietsDto)
    {
        return TheAnswer == TheAnswerCheckImplementation(answerIngredietsDto);
    }
}

//generate a base class
public class IngredientsAnswerChecker : IAnswerCheck //: TheAnswerChecker<IngredientDto>
{
    public bool CheckAnswer<T, DTO>(T answerCkecker, DTO ingredientsDto) 
        where T : TheAnswerChecker<DTO>
        where DTO : IngredientDto
    {
        return answerCkecker.IsTheAnswerCheckImplementationTheAnswer(ingredientsDto);
    }
}

public class TwoIngredientsMultiplicationAnswerChecker : TheAnswerChecker<TwoIngredientsDto>
{
    internal override int TheAnswerCheckImplementation(TwoIngredientsDto answerIngredietsDto) //where T : TwoIngredientsDto
    { 
        return answerIngredietsDto.A * answerIngredietsDto.B;
    }
}

public class ThreeIngredientsAdditionAnswerChecker : TheAnswerChecker<ThreeIngredientsDto>
{
    internal override int TheAnswerCheckImplementation(ThreeIngredientsDto answerIngredietsDto)
    {
        return answerIngredietsDto.A + answerIngredietsDto.B + answerIngredietsDto.C;
    }
}

public class IngredientDto
{
    public IngredientDto()
    {
        Id = Guid.NewGuid();
    }
    public Guid Id { get; private set; }
}

public class TwoIngredientsDto : IngredientDto
{
    public virtual int A {get {return 6;}}
    public virtual int B {get {return 7;}} 
}

public class ThreeIngredientsDto : TwoIngredientsDto
{
    public override int B {get {return 24;}} 
    public int C {get {return 12;}} 
}

【问题讨论】:

    标签: c# generics polymorphism dto solid-principles


    【解决方案1】:

    DTO 背后的想法是使用 dummy/plain 对象进行数据传输,因此您应该避免向此类对象增加复杂性,例如通过继承,否则 DTO 将失去其简单和序列化友好的主要目的。

    关于您的“演员问题”,答案是肯定的,演员将允许使用 ThreeIngredientsDto 而不是 TwoIngredientsDto。

    对于私有属性“TheAnswer”,我建议使用 const。

    总体而言,您的示例尊重 SOLID 原则,但请注意,并非总是必须将代码拆分为原子片段以实现单一职责原则。例如,我不使用 TwoIngredientsMultiplicationAnswerCheckerThreeIngredientsAdditionAnswerCheckerTheAnswerChecker 类,而是使用单个类 TheAnswerChecker每种类型的 DTO 都有一个重载方法,这样您的代码将更具可读性和可理解性,毕竟,您的班级责任只是检查答案。当然,如果为每种类型的 DTO 检查答案的逻辑将非常复杂并且需要大量代码,那么拆分为不同的类可能是有意义的。关键是 SOLID 应该代表一组在构建代码时要牢记的原则,但有时违反某些规则会带来很多好处,在这种情况下,您应该做出这种妥协。

    【讨论】:

      猜你喜欢
      • 2011-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-27
      • 2021-10-09
      • 2022-01-26
      • 1970-01-01
      相关资源
      最近更新 更多