用代码解释接口和抽象类

代码设计逻辑:
假设我们在玩一款游戏,玩家要操纵不同的军队来攻击敌人,还可以建造防御塔加强基地防御,军队有的不能移动,有的可以在陆地上跑,有的可以驾驶飞机,驾驶轮船等等。
可执行代码如下:
(例子仅供参考,具体设计要根据实际的业务逻辑来决定)
定义军队抽象类

	/// <summary>
    /// 军队抽象类
    /// </summary>
    public abstract class Force//默认不会移动
    {
        //军队都有名字,都会攻击敌人,侦察敌人,但不一定都会移动,例如防御塔
        public string name { get; set; }//属性:姓名
        public Force(string name)
        { 
            this.name = name; 
        }
        public abstract void Attack(Enemy ad);//军队都会攻击敌人,但攻击方式不同,所以定义抽象方法,让派生类自己实现
        public void Scout(Enemy ad)//侦察敌人,假设每一种军队都用眼睛侦察,即派生类具有相同的行为,则无需让派生类单独实现,可以在抽象类中实现,减少代码冗余
        {
            Console.WriteLine($"{name}看到了{ad.name}");
        }
    }

然后定义移动接口

 	/// <summary>
    /// 空中移动接口
    /// </summary>
    interface IAirMove
    {
        void AirMove();
    }
    /// <summary>
    /// 陆地移动接口
    /// </summary>
    interface ILandMove
    {
        void LandMove();
    }
    /// <summary>
    /// 海上移动接口
    /// </summary>
    interface ISeaMove
    {
        void SeaMove();
    }

接着让派生类去继承军队抽象类,以及实现它们符合需求的接口

	/// <summary>
    /// 陆军类
    /// </summary>
    public class Army : Force, ILandMove
    {
        public Army(string name):base(name){}
        public void LandMove()
        {
            Console.WriteLine($"{name}通过跑步在陆地上移动");
        }
        public override void Attack(Enemy ad)
        {
            Console.WriteLine($"{name}通过AK-47攻击{ad.name}");
        }
    }
	/// <summary>
    /// 空军类
    /// </summary>
    public class AirForce : Force, IAirMove
    {
        public AirForce(string name) : base(name) { }
        public override void Attack(Enemy ad)
        {
            Console.WriteLine($"{name}通过飞机上的加特林攻击{ad.name}");
        }

        public void AirMove()
        {
            Console.WriteLine($"{name}驾驶直升机在天空中移动");
        }
    }
	/// <summary>
    /// 海军陆战队类
    /// </summary>
    public class SeaForce : Force, ISeaMove, ILandMove
    {
        public SeaForce(string name) : base(name) { }
        public override void Attack(Enemy ad)
        {
            Console.WriteLine($"{name}通过两栖车上的导弹攻击{ad.name}");
        }

        public void LandMove()
        {
            Console.WriteLine($"{name}通过两栖车在陆地上移动");
        }

        public void SeaMove()
        {
            Console.WriteLine($"{name}通过两栖车在海洋中移动");
        }
    }

接着简单定义一下敌人类

public class Enemy
    {
        public string name;
        public Enemy(string name)
        {
            this.name = name;
        }
    }

类已经定义完毕,该测试看看效果了
先定义一个封装操作的测试类,供调用者调用

class Test
    {
        //通过陆地移动军队
        public static void MoveForceByLand(ILandMove lm)
        {
            lm.LandMove();
        }
        //通过天空移动军队
        public static void MoveForceByAir(IAirMove am)
        {
            am.AirMove();
        }
        //通过海洋移动军队
        public static void MoveForceBySea(ISeaMove sm)
        {
            sm.SeaMove();
        }
        //军队攻击敌人
        public static void Combat(Force force, Enemy enemy)
        {
            force.Scout(enemy);
            force.Attack(enemy);
        }
    }

调用者在Main函数中调用

static void Main(string[] args)
        {
            Army army1 = new Army("陆军1号");
            Army army2 = new Army("陆军2号");
            Army army3 = new Army("陆军3号");
            AirForce air1 = new AirForce("空军1号");
            AirForce air2 = new AirForce("空军2号");
            SeaForce sea1 = new SeaForce("海军陆战队");
            Enemy e1 = new Enemy("厄加特");
            Test.MoveForceByLand(army1);
            Test.MoveForceByLand(army2);
            Test.MoveForceByLand(army3);
            Test.MoveForceByAir(air1);
            Test.MoveForceByAir(air2);
            Test.MoveForceBySea(sea1);
            Test.MoveForceByLand(sea1);
            Test.Combat(army1, e1);
            Test.Combat(air2, e1);
            Test.Combat(sea1, e1);
            Console.ReadKey();
        }

运行结果显示:
在这里插入图片描述
代码分析:

从代码中,可以看出,用户(即调用者)在调用我们封装的代码时,只需知道对象能做什么,无需知道具体是怎么做的,在函数内部调用过程中,实现类隐式转换为接口或抽象类,即向上转型,无需转型操作符。实现类的实例总是包含接口或抽象类的全部成员,所以总是能成功转换接口或抽象类类型。通过向上转型实现多态,提高了程序的可扩展性。
对于接口和抽象类的区别,很多文章已经解释的非常清楚,作者这里叙述一下自己认为最重要的:
1.抽象类中的成员可以有实现,作用是减少代码冗余,提高代码的复用性,接口中不能有实现,所以抽象类是不完全抽象,接口是完全抽象。
2.派生类只能从一个抽象类中派生(C#和Java为单继承),但可以实现任意多个接口
至于其他的一些细节,相信聪明的你能够通过代码和以后的工作学习中慢慢体会的。
特别说明,设计模式的核心原则就是面向接口编程,面向抽象编程。理解抽象类和接口,对理解设计模式有极大的帮助。
一句话总结
掌握一个知识,就要能用一句话去概括。
接口和抽象类都是更高层次的抽象。抽象类是对事物本质的抽象,它约束了对象是什么?接口是对行为的抽象,它约束了对象能做什么?
使用时机:
当你关注对象的本质时,用抽象类,当你关注对象的行为时,用接口。(好吧,我承认不是一句了)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值