2016-01-21 1 views
0

Я упомянул, что я не очень много работал с DTO. Я играю с полимофизмом в DataTransfereObjects. Я не мог найти хорошее решение, поэтому я сделал этот код, чтобы справиться с полиморфизмом с DataTransfereObjects и другой логической реализацией, использует полиморфизм, генерики, интерфейсы, абстрактные и так далее.Освоение dto polimorphism

Проверьте код. Подскажите мне, что плохо, можно сделать лучше или проще. Проверьте accessmodifier, также проверьте против SOLID (думаю, я не понял его правильно). В конце это кажется слишком сложным, часто ли это решать?

На самом деле, я пытаюсь вызвать некоторый (de) serialize programlogic, который использует baseDto для получения dtos без потери их конкретной информации. Этот код должен быть чистой песочницей абстракции для таких проблем.

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;}} 
} 

ответ

0

Идея DTOS заключается в использовании фиктивных/простые объекты для передачи данных, поэтому вы должны избегать добавления сложности, например, путем наследования, такого рода объекты, в противном случае DTOS потеряет свою основную цель, чтобы быть простым и сериализации.

Что касается вашего «вопроса о литье», то да, бросок позволит использовать ThreeIngredientsDto вместо TwoIngredientsDto.

Для частной собственности «TheAnswer» я бы предложил использовать const.

В целом ваш пример относится к принципам SOLID, но остерегайтесь не всегда, мы должны разделить наш код на атомные кусочки для достижения принципа единой ответственности. Например, вместо того TwoIngredientsMultiplicationAnswerChecker, ThreeIngredientsAdditionAnswerChecker и TheAnswerChecker классы, я хотел бы использовать один класс TheAnswerChecker, которая будет иметь метод перегрузки для каждого типа DTO, таким образом ваш код будет более читабельным и более понятно, и в конце концов, ответственность за ваш класс будет только для проверки ответа. Конечно, если логика проверки ответа для каждого типа DTO будет очень сложной и потребует большого количества кода, то, вероятно, будет иметь смысл разделить в разных классах. Дело в том, что SOLID должен представлять собой набор принципов, которые следует учитывать при составлении кода, но иногда нарушение некоторых правил может принести много преимуществ, и в этом случае вы должны выполнить этот компромисс.