通过创建一个类来支持新类型的灵活创建,其每个实例都代表一个不同的对象类型。
问题
试着想象一下,如果我们来设计一个怪物的数据我们会如何?
以及我们的Attack行为。
可以想到诸如这些的属性,在以这些数据的基础上来派生更多的特殊化数据。
传统设计
按照我们的常规思维,我们很容易想到如下的设计方案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public abstract class MosterBase { public string Name { get; set; }
public int Hp { get; set; }
public string Race { get; set; }
public int Damage { get; set; }
protected virtual void Attack() { } }
public class BigCat : MosterBase { protected override void Attack() { base.Attack(); Console.WriteLine("喵!"); } }
public class Elf: MosterBase { protected override void Attack() { base.Attack(); Console.WriteLine("精灵攻击"); } }
|
假如,此时我们希望怪物的数值和种族挂钩。
我们第一时间想到的肯定是将种族也划分为一个类。
于是我们有了以下的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class Race { public string Name { get; set; }
public int Hp { get; set; }
public int Damage { get; set; } }
public abstract class MosterBase { public string Name { get; set; }
public int Hp { get; set; } public int Damage { get; set; }
public Race Race { get; set; }
protected virtual void Attack() { } }
|
Race类可以帮助我们存放所有同种族 怪物的共享信息。
这种,类似组合的设计方案,帮助我们共享一部分数据,但在行为层面 也导致了我们子类过多的问题。
使用类型对象
在类中放置一个对象引用来表述类型,通过怪物+种族的组合方式,来解决子类过多的设计。
❤️ 放置的对象引用已经表述了类型,就无需通过继承来表达关系。
❤️ 通过类型对象搭建工厂生成对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| class Program { static void Main(string[] args) {
var breed = new Breed { AttackLevel = 5, BaseHp = 50, Name = "狼" }; Console.WriteLine(new Moster() { Hp = 100, Name = "灰狼", Breed = breed }); Console.WriteLine(new Moster() { Hp = 50, Name = "白狼", Breed = breed });
Console.WriteLine(breed.NewMoster());
var breed2 = new Breed { AttackLevel = 6, Name = "死灵狼", Parent = breed };
var mos = breed2.NewMoster("恐怖之狼");
Console.WriteLine(breed2);
}
}
class Moster { public Breed Breed { get; set; }
public int Hp { get; set; }
public int SumHp => Breed.BaseHp + Hp;
public string Name { get; set; }
public override string ToString() { return $"{Name} HP:{SumHp} breedName:{Breed.Name} AttackLevel:{Breed.AttackLevel}"; } }
class Breed { public string Name { get; set; }
public int AttackLevel { get; set; }
private int baseHp; public int BaseHp { get { if (baseHp == 0 && Parent != null) { return Parent.baseHp; }
return baseHp; } set { baseHp = value; } }
public Moster NewMoster(string name = "") { return new Moster() { Breed = this, Name = name }; }
public Breed Parent { get; set; }
public override string ToString() { return $"{Parent.Name}->{Name} AttackLevel:{AttackLevel} BaseHp:{BaseHp}"; }
}
|