通过创建一个类来支持新类型的灵活创建,其每个实例都代表一个不同的对象类型。

# 问题

试着想象一下,如果我们来设计一个怪物的数据我们会如何?

  • 名称
  • 种族
  • 生命值
  • 攻击力

以及我们的 Attack 行为。

可以想到诸如这些的属性,在以这些数据的基础上来派生更多的特殊化数据。

# 传统设计

按照我们的常规思维,我们很容易想到如下的设计方案。

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("精灵攻击");
    }
}

假如,此时我们希望怪物的数值和种族挂钩。

我们第一时间想到的肯定是将 种族 也划分为一个类。

于是我们有了以下的代码:

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 类可以帮助我们存放所有同种族 怪物的共享信息。

这种,类似组合的设计方案,帮助我们共享一部分数据,但在行为层面 也导致了我们子类过多的问题。

# 使用类型对象

在类中放置一个对象引用来表述类型,通过怪物 + 种族的组合方式,来解决子类过多的设计。

❤️ 放置的对象引用已经表述了类型,就无需通过继承来表达关系。

❤️ 通过类型对象搭建工厂生成对象。

class Program
    {
        static void Main(string[] args)
        {
            /*
             * 类型对象:是指通过组合的方式去解决继承导致的强耦合问题
             * 例如:在下面的例子中,如果我们将种族放在 Moster 中,然后通过继承的方式实现抽象类 Moster,会导致子类过多,耦合强。
             * 使用一个单独的对象将种族抽离出来,通过怪物和种族的组合方式就可以创建不同的怪物。
             */
            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(mos);
            Console.WriteLine(breed2);
        }
    }
    /// <summary>
    /// 怪物
    /// </summary>
    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}";
        }
    }
    /// <summary>
    /// 种族
    /// </summary>
    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; }
        }
        // 可以通过这种方式为种族添加一个方法工厂化生成 Moster
        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}";
        }
    }
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Fasty 微信支付

微信支付

Fasty 支付宝

支付宝

Fasty 贝宝

贝宝