C#继承重载与接口的引入(二)

2021-02-02 06:15

阅读:563

标签:显示   方法   父类   private   对象   参与   his   思想   冗余   

这篇是对上篇的补充,和之前计划的有点小差异,多层次继承需要再往后靠靠了,还是先看代码

namespace ConsoleApp1
{

    public interface It
    {
        void PI();
    }

    public class A:It
    {
        private int _type = 0;
        public int Type = 0;

        public A(int type)
        {
            Type = _type = type;
        }

        public virtual void P()
        {
            Console.WriteLine("这是A的PP!");
        }

        public virtual void PI()
        {
            Console.WriteLine("这是A的PI!");
        }

        public void Dispatch()
        {
            switch (_type)
            {
                case 1:
                    (this as B).P();
                    break;
                case 2:
                    (this as C).P();
                    break;
            }
        }
    }

    public class B : A
    {
        public B(int type) : base(type) { }

        public override void P()
        {
            Console.WriteLine("这是B的PP!");
        }

        public override void PI()
        {
            Console.WriteLine("这是B的PI!");
        }
    }

    public class C : A
    {
        public C(int type) : base(type) { }

        public override void P()
        {
            Console.WriteLine("这是C的PP!");
        }

        public override void PI()
        {
            Console.WriteLine("这是C的PI!");
        }
    }
}

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            _dictClass.Add(0, new A(0));
            _dictClass.Add(1, new B(1));
            _dictClass.Add(2, new C(2));

            _dictInterface.Add(0, new A(0));
            _dictInterface.Add(1, new B(1));
            _dictInterface.Add(2, new C(2));

            _dictClass[0].P();
            Console.WriteLine(_dictClass[0].Type);
            _dictClass[1].P();
            Console.WriteLine(_dictClass[1].Type);
            _dictClass[2].P();
            Console.WriteLine(_dictClass[2].Type);

            Console.WriteLine();
            Console.WriteLine("ding------------------------------ding");
            Console.WriteLine();

            _dictClass[1].Dispatch();
            _dictClass[2].Dispatch();

            Console.WriteLine();
            Console.WriteLine("ding------------------------------ding");
            Console.WriteLine();

            _dictInterface[0].PI();
            _dictInterface[1].PI();
            _dictInterface[2].PI();
        }

        private static Dictionaryint, It> _dictInterface = new Dictionaryint, It>();
        private static Dictionaryint, A>  _dictClass = new Dictionaryint, A>();
    }

}

再看看结果:

技术图片

先来解释下,这一次测试对代码进行了稍微的改进,引入了两个变量,同时加了一个Dispatch

A b = new B(1);

这个变量的引入是为了更加直观的描述这一行代码,首先构造B实例,B继承A因此在B构造之前先对A进行了构造,

并且在父类构造的同时,赋值变量Type、_type 都为1,而Type是public的可以被子类继承

因此b.Type = 1,这样相比应该都明白了吧,而c是和它一样的,就不再说了。

可能你已经发现了,引入的_type与Dispatch关联到了一块了,

没错,我用它来进行指令的分派,也就是做动态管理时会经常用到的,这样一来,子类继承自父类时可以不用重载父类的方法就能实现一些额外的功能,而这个父类就变成了一个转发器。

实际上这种写法并不好,父类是不应该参与子类的具体行为的,所以我打算再修改一下。

namespace ConsoleApp1
{

    public interface It
    {
        void PI();
    }

    public class A:It
    {
        private int _type = 0;
        public int Type = 0;
        public A a;

        public A(int type)
        {
            Type = _type = type;
        }

        public virtual void P()
        {
            Console.WriteLine("这是A的PP!");
        }

        public virtual void PI()
        {
            Console.WriteLine("这是A的PI!");
        }

        public void Dispatch()
        {
            Console.WriteLine("这里是指令分派的接口哦!");
            a.P();
        }
    }

    public class B : A
    {
        public B(int type) : base(type) {
            a = this;
        }

        public override void P()
        {
            Console.WriteLine("这是B的PP!");
        }

        public override void PI()
        {
            Console.WriteLine("这是B的PI!");
        }
    }

    public class C : A
    {
        public C(int type) : base(type) {
            a = this;
        }

        public override void P()
        {
            Console.WriteLine("这是C的PP!");
        }

        public override void PI()
        {
            Console.WriteLine("这是C的PI!");
        }
    }
}

你应该看出来了,这里去掉了_type与switch,改用实例本身来进行指令分派

来看看结果

技术图片

结果和之前是一样的,这样一来,就避免了父类对子类的干预,而仅仅只是作为一个转发器。

看到这里,你应该会疑惑,这样写有什么意义呢?直接掉子类的重载方法不就行了吗,何必多此一举呢?

没错,这样做的确画蛇添足,但如果子类不进行重载的话,那么会怎么样子呢?

 

namespace ConsoleApp1
{

    public interface It
    {
        void PI();
    }

    public class A:It
    {
        private int _type = 0;
        public int Type = 0;
        public A a;

        public A(int type)
        {
            Type = _type = type;
        }

        public void P()
        {
            Console.WriteLine("这是A的PP!");
        }

        public virtual void PI()
        {
            Console.WriteLine("这是A的PI!");
        }

        public void Dispatch()
        {
            Console.WriteLine("这里是指令分派的接口哦!");
            a.P();
        }
    }

    public class B : A
    {
        public B(int type) : base(type) {
            a = this;
        }

        public new void P()
        {
            Console.WriteLine("这是B的PP!");
        }

        public override void PI()
        {
            Console.WriteLine("这是B的PI!");
        }

        public void PP()
        {

        }
    }

    public class C : A
    {
        public C(int type) : base(type) {
            a = this;
        }

        public new void P()
        {
            Console.WriteLine("这是C的PP!");
        }

        public override void PI()
        {
            Console.WriteLine("这是C的PI!");
        }

        public void PP()
        {
            Console.WriteLine("这是C的PP!");
        }
    }
}

 

看看结果

技术图片

无论是哪一种,似乎都没什么用了,这是因为,我在接收实例的时候统统转化为A声明的实例,这样一来,没有进行重载的话,这些实例即使拥有和父类相同的方法,也只能以父类为模板进行表现,要想实现子类的特性,必须将这个实例重新转化为它的构造类型,如(b as B).PP();

下面看张图

技术图片

这张图很很好的解释了刚才说的。

如此一来,如果想实现父类对子类的管理,那么子类被管理的方法必须要被重载才行,在笔者理解来,重载就像是一个关联起来的映射,如果这个映射存在,那么这个方法呈现的效果就是子类的效果,如果不存在,那就只显示父类结果,父类就像是一个小箱子,子类就像是一个大箱子包裹着父类这个小箱子,若果两者之间有映射,那么父类可以沿着这条线来操纵子类在大箱子里表演,否则只能在里面的小物体自导自演了。

这样的话,似乎这个负责管理的转发器也并不是很好用啊,或许你可以多写几个虚函数来对子类行为进行映射扩充,但这似乎并不符合面向对象编程的思想,而且行为上很相似抽象和接口,会造成很多的冗余。

那么问题来了,写这篇扩展的意义是什么呢?

两个方面,

一是想看看面向对象的编程,父与子的关系究竟如何。

二和编写框架有关,按照笔者的思路,框架的管理思想是由上到下,最上级是管理者和协调者,能够统一的处理一类事情,而下级则是具体的执行者,看上去很像父子的继承关系,实际上也确实是这样的。

大概是笔者比较转牛角尖,总是希望所有的对象都能通过一个管理者来协调,虽然最后通过组合模块的方式也实现了,但距离笔者想要的结果还是有点差距,因此才往这方面进行了一些研究,虽然结果并不一定是自己想要的,但重要的是思考问题的方式,以及过程中的收获。

那么在这里结束这篇没有结果的思路吧,下一篇开始多层次继承的研究。

 

C#继承重载与接口的引入(二)

标签:显示   方法   父类   private   对象   参与   his   思想   冗余   

原文地址:https://www.cnblogs.com/fairy-blonde/p/11562827.html


评论


亲,登录后才可以留言!