为实现抽象的多个类创建一个DTO是一种不好的做法吗?



例如:

我有:

  • 抽象类 具有属性名称的动物
  • 狗工具动物并具有财产国家
  • 猫养动物并具有属性大小

我可以按以下方式使用 DTO 吗?

AnimalDto {
public string Name { get; set;} 
public string Country { get; set;}
public string Size { get; set;}
public AnimalType Type { get; set}
}

要回答这个问题,你可以看看SOLID原则,尤其是单一责任原则,它指出一个类必须只有一个理由来改变。

如果你的 DTO 重新组合了属于动物王国的所有类的所有属性,那么每次需要更改这些类中的每一个时,它都必须更改。如果 Cat 发生变化,它将发生变化。如果狗改变,它会改变。等等。我会避免这种情况。

正如其他答案中所述,如果可能的话,可能值得重新考虑设计。

这个呢:

public abstract AnimalDTO
{
public static AnimalDTO Create(Animal animal)
{
var dog = animal as Dog;
var cat = animal as Cat;
if (dog != null)
{
return Dog(dog.Country);
}
else
{
return Cat(cat.Size);
}
}
public static AnimalDTO Dog(string country) => 
new Animals.Dog(country);
public static AnimalDTO Cat(string size) =>
new Animals.Cat(size);
public abstract void Switch(Action<string> isDog, Action<string> isCat);
private static class Animals
{
public class Dog : AnimalDTO
{
readonly string country;
public Dog(string country)
{
this.country = country;
}
public override void Switch(Action<string> isDog, Action<string> isCat) => isDog(country);
}
public class Cat : AnimalDTO
{
readonly string size;
public Dog(string size)
{
this.size = size;
}
public override void Switch(Action<string> isDog, Action<string> isCat) => isCat(size);
}
}

例如:

public void CallFactory(Animal animal)
{
var a = AnimalDTO.Create(animal);
Factory(a);
}
public void Factory(AnimalDTO animal)
{
animal.Switch(
isDog: (country) => {
// here you can be sure that the animal is dog
// you can use country variable
Console.Writeline($"It is a dog! from country {country}");
},
isCat: (size) => {
// it is a cat
Console.Writeline($"it is a cat of size {size}");
});
}

我觉得这是一个XY问题。为什么要使用抽象类?

有一种方法可以避免创建抽象类 - 除了必须从您正在使用但无法控制的库中子类化抽象。如何?使用接口,当您需要通用功能时,使用静态函数或将组合与另一个类一起使用。

我知道这不是对你的问题的直接回答,但它可能会解决你的问题。

public interface IAnimal
{
string Name { get; set; }
}
public class Dog : IAnimal
{
public string Name { get; set; }
public string Country { get; set; }
}
public class Cat : IAnimal
{
public string Name { get; set; }
public string Size { get; set; }
}

由此,您最终会得到两个类,这两个类都可以用作 DTO,但它们都没有不必要的属性。

在运行时,您可以键入检查。

IAnimal myAnimal = ... ;
Helpers.DoSomethingWithAnimal(myAnimal);
switch (myAnimal)
{
case (Cat cat):
Helpers.DoSomethingWithCat(cat);
break;
case (Dog dog):
Helpers.DoSomethingWithDog(dog);
break;
}

序列化时,可以插入一个额外的属性来跟踪需要将数据反序列化为哪种类型的动物。

{
name: "My Dog",
country: "Romania",
"__animal-type": "dog"
}

相关内容

最新更新