如何正确创建并行继承层级?C#动物类与颜色数据类场景示例
问题描述
我有一个基于C#和MonoBehaviour的动物继承层级,原始代码如下:
abstract class Animal : MonoBehaviour { public int Health; public Color MainColor; public virtual bool HasColor(Color color) { return MainColor == color; } } abstract class CarnivorousAnimal : Animal { public int Damage; public List<Color> SecondaryColors; public override bool HasColor(Color color) { return base.HasColor(color) || SecondaryColors.Contains(color); } } class Cat : CarnivorousAnimal { public float MeowLoudness; public Color FurColor; public override bool HasColor(Color color) { return base.HasColor(color) || FurColor == color; } }
为了遵循单一职责原则(SRP),我打算把所有与颜色相关的数据和方法迁移到独立的并行层级(AnimalColorData、CarnivorousAnimalColorData、CatColorData),通过ColorData字段关联。颜色数据类代码如下:
class AnimalColorData { public Color MainColor; public virtual bool HasColor(Color color) { return MainColor == color; } } class CarnivorousAnimalColorData : AnimalColorData { public List<Color> SecondaryColors; public override bool HasColor(Color color) { return base.HasColor(color) || SecondaryColors.Contains(color); } } class CatColorData : CarnivorousAnimalColorData { public Color FurColor; public override bool HasColor(Color color) { return base.HasColor(color) || FurColor == color; } }
我最初尝试修改动物层级为如下结构,但这段代码存在问题:Cat类会拥有3份ColorData字段,属于隐藏基类成员的错误实现,无法正常工作:
abstract class Animal : MonoBehaviour { public int Health; public AnimalColorData ColorData; } abstract class CarnivorousAnimal : Animal { public int Damage; public CarnivorousAnimalColorData ColorData; } class Cat : CarnivorousAnimal { public float MeowLoudness; public CatColorData ColorData; }
我期望实现的效果是:同一个Cat实例的ColorData在不同类型的引用下,能正确访问对应层级的颜色数据和方法,示例代码如下:
Cat cat = new Cat(); cat.ColorData.MainColor = Color.green; cat.ColorData.FurColor = Color.cyan; CarnivorousAnimal animal = cat; Console.WriteLine(animal.ColorData.HasColor(Color.cyan)); // 期望输出false Console.WriteLine(cat.ColorData.HasColor(Color.cyan)); // 期望输出true
另外,我认为泛型不是最优解,因为每次使用基类时都必须指定类型。请问该如何正确实现?
解决方案
方法1:基类用受保护字段+子类强类型属性(推荐)
将基类的ColorData设为受保护字段存储实例,子类通过公共属性返回该字段的强转版本,这样所有层级共享同一个ColorData实例,不会产生重复:
abstract class Animal : MonoBehaviour { public int Health; // 受保护字段,存储实际的ColorData实例 protected AnimalColorData _colorData; // 对外暴露基类类型的ColorData属性 public AnimalColorData ColorData => _colorData; // 构造函数初始化,确保子类可以传入对应类型的实例 protected Animal(AnimalColorData colorData) { _colorData = colorData; } } abstract class CarnivorousAnimal : Animal { public int Damage; // 子类的强类型属性,返回转换后的ColorData public new CarnivorousAnimalColorData ColorData => (CarnivorousAnimalColorData)_colorData; protected CarnivorousAnimal(CarnivorousAnimalColorData colorData) : base(colorData) { } } class Cat : CarnivorousAnimal { public float MeowLoudness; // Cat层级的强类型属性 public new CatColorData ColorData => (CatColorData)_colorData; // 构造函数传入CatColorData实例,确保类型匹配 public Cat() : base(new CatColorData()) { } }
使用时完全符合预期效果:
Cat cat = new Cat(); cat.ColorData.MainColor = Color.green; cat.ColorData.FurColor = Color.cyan; CarnivorousAnimal animal = cat; Console.WriteLine(animal.ColorData.HasColor(Color.cyan)); // 输出false(调用AnimalColorData的HasColor) Console.WriteLine(cat.ColorData.HasColor(Color.cyan)); // 输出true(调用CatColorData的HasColor)
方法2:显式接口实现
如果希望彻底避免字段隐藏的警告,可以定义泛型接口,让每个层级显式实现对应类型的接口:
// 定义泛型接口,用于获取特定类型的ColorData public interface IHasColorData<T> where T : AnimalColorData { T ColorData { get; } } abstract class Animal : MonoBehaviour, IHasColorData<AnimalColorData> { public int Health; protected AnimalColorData _colorData; // 显式实现接口 AnimalColorData IHasColorData<AnimalColorData>.ColorData => _colorData; // 对外的非泛型属性,方便直接访问基类ColorData public AnimalColorData ColorData => _colorData; protected Animal(AnimalColorData colorData) { _colorData = colorData; } } abstract class CarnivorousAnimal : Animal, IHasColorData<CarnivorousAnimalColorData> { public int Damage; // 显式实现接口 CarnivorousAnimalColorData IHasColorData<CarnivorousAnimalColorData>.ColorData => (CarnivorousAnimalColorData)_colorData; // 子类的强类型属性 public new CarnivorousAnimalColorData ColorData => (CarnivorousAnimalColorData)_colorData; protected CarnivorousAnimal(CarnivorousAnimalColorData colorData) : base(colorData) { } } class Cat : CarnivorousAnimal, IHasColorData<CatColorData> { public float MeowLoudness; // 显式实现接口 CatColorData IHasColorData<CatColorData>.ColorData => (CatColorData)_colorData; // Cat层级的强类型属性 public new CatColorData ColorData => (CatColorData)_colorData; public Cat() : base(new CatColorData()) { } }
这种方式既可以通过接口获取特定类型的ColorData,也能保持层级结构的清晰性。
内容的提问来源于stack exchange,提问作者Eugen1344
相关产品推荐
相关产品推荐

