15.里氏替换原则

15.面向对象-继承-里氏替换原则


15.1 知识点

里氏替换原则的基本概念

  • 里氏替换原则是面向对象七大原则中最重要的原则
    • 概念:任何父类出现的地方,子类都可以替代
    • 语法表现:父类容器装子类对象,因为子类对象包含了父类的所有内容
    • 作用:方便进行对象存储和管理

里氏替换原则的基本实现

class语句块外 namespace语句块内

//游戏对象类
class GameObject
{

}

//玩家类
class Player : GameObject
{
    public void PlayerAtk()
    {
        Console.WriteLine("玩家攻击");
    }
}

//怪物类
class Monster : GameObject
{
    public void MonsterAtk()
    {
        Console.WriteLine("怪物攻击");
    }
}

//Boss类
class Boss : GameObject
{
    public void BossAtk()
    {
        Console.WriteLine("Boss攻击");
    }

主函数内

//里氏替换原则 用父类容器 装载子类对象
// 父类 变量名 = new 子类();
GameObject player = new Player();
GameObject monster = new Monster();
GameObject boss = new Boss();

GameObject[] objects = new GameObject[] { new Player(), new Monster(), new Boss() };
//Player p = new GameObject();//报错 不能用子类容器装父类对象

isas

主函数内

is 和 as 的基本概念
// is:判断一个对象是否是指定类对象
// 返回值:bool  是为真 不是为假
// as:将一个对象转换为指定类对象
// 返回值:指定类型对象
// 成功返回指定类型对象,失败返回null
is 和 as 的基本语法
// 类对象 is 类名   该语句块 会有一个 bool 返回值 true 和 false
// 类对象 as 类名   该语句块 会有一个对象返回值 对象和 null
is 和 as 的实例
//用is判断容器是GameObject容器的变量player的真实类型是不是Player类
if (player is Player)
{
    //用as将变量player转换为容器是Player的对象 用Player容器装
    Player p1 = player as Player;

    //转换失败会返回空
    Player p2 = monster as Player;

    //转换成功可以直接使用PlayerAtk()方法
    p1.PlayerAtk();

    //一步到位的写法
    (player as Player).PlayerAtk();
}

//遍历objects数组
for (int i = 0; i < objects.Length; i++)
{
    //通过is和as具体判断,转换,转换成功后使用对应子类的内容
    if (objects[i] is Player)
    {
        (objects[i] as Player).PlayerAtk();
    }
    else if (objects[i] is Monster)
    {
        (objects[i] as Monster).MonsterAtk();
    }
    else if (objects[i] is Boss)
    {
        (objects[i] as Boss).BossAtk();
    }
}

总结

  • 概念:父类容器装子类对象
  • 作用:方便进行对象的存储和管理
  • 使用:isas 用于判断和用于转换
  • 注意:不能用子类容器装父类对象

15.2 知识点代码

using System;

namespace Lesson13_继承_里氏替换原则
{
    #region 知识点一 里氏替换原则的基本概念
    // 里氏替换原则是面向对象七大原则中最重要的原则
    // 概念:任何父类出现的地方,子类都可以替代
    // 重点:语法表现——父类容器装子类对象,因为子类对象包含了父类的所有内容
    // 作用:方便进行对象存储和管理
    #endregion

    #region 知识点二 里氏替换原则的基本实现

    //class语句块外 namespace语句块内

    //游戏对象类
    class GameObject
    {

    }

    //玩家类
    class Player:GameObject
    {
        public void PlayerAtk()
        {
            Console.WriteLine("玩家攻击");
        }
    }

    //怪物类
    class Monster:GameObject
    {
        public void MonsterAtk()
        {
            Console.WriteLine("怪物攻击");
        }
    }

    //Boss类
    class Boss:GameObject
    {
        public void BossAtk()
        {
            Console.WriteLine("Boss攻击");
        }
    }
    #endregion

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("里氏替换原则");

            //主函数内

            #region 知识点二 里氏替换原则的基本实现

            //里氏替换原则 用父类容器 装载子类对象
            // 父类 变量名 = new 子类();
            GameObject player = new Player();
            GameObject monster = new Monster();
            GameObject boss = new Boss();

            GameObject[] objects = new GameObject[] { new Player(), new Monster(), new Boss() };

            //Player p = new GameObject();//报错 不能用子类容器装父类对象
            #endregion

            #region 知识点三 关键字 is和as
            // is和as的基本概念 

            // is:判断一个对象是否是指定类对象
            // 返回值:bool  是为真 不是为假

            // as:将一个对象转换为指定类对象
            // 返回值:指定类型对象
            // 成功返回指定类型对象,失败返回null

            //is和as的基本语法
            // 类对象 is 类名   该语句块 会有一个bool返回值 true和false
            // 类对象 as 类名   该语句块 会有一个对象返回值 对象和null

            // is和as的实例

            //player.PlayerAtk();
            //报错 变量player的真实类型现在是Gameobject 不能直接使用PlayerAtk()方法

            //用is 判断容器是Gameobject容器的变量player的真实类型 是不是Player类
            if ( player is Player )
            {
                //用as 将变量player转换为容器是Player的对象 用Player容器装
                Player p1 = player as Player;

                //转换失败会返回空
                Player p2 = monster as Player;

                //转换成功可以直接使用PlayerAtk()方法
                p1.PlayerAtk();

                //一步到位的写法
                (player as Player).PlayerAtk();
            }

            //遍历objects数组
            for (int i = 0; i < objects.Length; i++)
            {
                //通过is和as具体判断,转换,转换成功后使用对应子类的内容
                if ( objects[i] is Player )
                {
                    (objects[i] as Player).PlayerAtk();
                }
                else if( objects[i] is Monster )
                {
                    (objects[i] as Monster).MonsterAtk();
                }
                else if (objects[i] is Boss)
                {
                    (objects[i] as Boss).BossAtk();
                }
            }

            #endregion
        }
    }
    //总结
    //概念:父类容器装子类对象
    //作用:方便进行对象的存储和管理
    //使用:is和as 用于判断和用于转换
    // 注意:不能用子类容器装父类对象
}

15.3 练习题

is和as的区别

  • is 用于判断一个类对象是否是某一个类型的对象,返回 bool
  • as 用于尝试将一个类对象转换成指定类型的对象,如果成功返回该类型的对象,否则返回 null

写一个Monster类,它派生出Boss和Goblin两个类,Boss有技能;小怪有攻击;随机生成10个怪,装载到数组中,遍历这个数组,调用他们的攻击方法,如果是boss就释放技能

class语句块外 namespace语句块内

//怪物类
class Monster
{

}

//Boss类
class Boss : Monster
{
    public void Skill()
    {
        Console.WriteLine("boss技能");
    }
}

//哥布林类
class Goblin : Monster
{
    public void Atk()
    {
        Console.WriteLine("哥布林攻击");
    }
}

主函数内

// 主函数内
//随机变量
Random r = new Random();
int randomNum;

//声明怪物数组
Monster[] monsters = new Monster[10];

//随机生成10个怪物 装载到怪物数组中
for (int i = 0; i < monsters.Length; i++)
{
    randomNum = r.Next(1, 101);

    //各百分之50的机会生成boss和哥布林
    if (randomNum < 50)
    {
        monsters[i] = new Boss();
    }
    else
    {
        monsters[i] = new Goblin();
    }
}

//遍历10个怪物 执行对应子类的攻击方法
for (int i = 0; i < monsters.Length; i++)
{
    if (monsters[i] is Boss)
    {
        (monsters[i] as Boss).Skill();
    }
    else
    {
        (monsters[i] as Goblin).Atk();
    }
}

FPS游戏模拟

写一个玩家类,玩家可以拥有各种武器
现在有四种武器,冲锋枪,散弹枪,手枪,匕首
玩家默认拥有匕首
请在玩家类中写一个方法,可以拾取不同的武器替换自己拥有的武器

class语句块外 namespace语句块内

//武器类
class Weapon
{

}
//冲锋枪
class SubmachineGun : Weapon
{

}
//散弹枪
class ShotGun : Weapon
{

}
//手枪
class Pistol : Weapon
{

}
//匕首
class Dagger : Weapon
{

}

//玩家类
class Player
{
    //玩家现在持有的武器
    private Weapon nowHaveWeapon;

    public Player()
    {
        //玩家构造时 默认拥有匕首
        nowHaveWeapon = new Dagger();
    }

    //拾取切换武器方法 传入武器 可以是子类
    public void PickUp(Weapon weapon)
    {
        nowHaveWeapon = weapon;
    }
}

主函数内

// 主函数内
//创建玩家
Player p = new Player();

//创建冲锋枪
SubmachineGun s = new SubmachineGun();
//拾取冲锋枪
p.PickUp(s);

//创建散弹枪
ShotGun sg = new ShotGun();
//拾取散弹枪
p.PickUp(sg);

15.4 练习题代码

using System;

namespace Lesson13_练习题
{
    #region 练习题一
    //is和as的区别是什么

    // is 用于判断  类对象判断是不是某一个类型的对象   bool 
    // as 用于转换  把一个类对象 转换成一个指定类型的对象   null
    #endregion

    //class语句块外 namespace语句块内

    #region 练习题二
    //写一个Monster类,它派生出Boss和Goblin两个类,
    //Boss有技能;小怪有攻击;
    //随机生成10个怪,装载到数组中
    //遍历这个数组,调用他们的攻击方法,如果是boss就释放技能

    //怪物类
    class Monster
    {

    }

    //Boss类
    class Boss : Monster
    {
        public void Skill()
        {
            Console.WriteLine("boss技能");
        }
    }

    //哥布林类
    class Goblin:Monster
    {
        public void Atk()
        {
            Console.WriteLine("哥布林攻击");
        }
    }

    #endregion

    #region 练习题三
    //FPS游戏模拟
    //写一个玩家类,玩家可以拥有各种武器
    //现在有四种武器,冲锋枪,散弹枪,手枪,匕首
    //玩家默认拥有匕首
    //请在玩家类中写一个方法,可以拾取不同的武器替换自己拥有的武器

    //武器类
    class Weapon
    {

    }
    //冲锋枪
    class SubmachineGun : Weapon
    {

    }
    //散弹枪
    class ShotGun : Weapon
    {

    }
    //手枪
    class Pistol : Weapon
    {

    }
    //匕首
    class Dagger:Weapon
    {

    }
    
    //玩家类
    class Player
    {
        //玩家现在持有的武器
        private Weapon nowHaveWeapon;

        public Player()
        {
            //玩家构造时 默认拥有匕首
            nowHaveWeapon = new Dagger();
        }

        //拾取切换武器方法 传入武器 可以是子类
        public void PickUp(Weapon weapon)
        {
            nowHaveWeapon = weapon;
        }
    }

    #endregion

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("里氏替换练习题");

            //主函数内

            #region 练习题二

            //随机变量
            Random r = new Random();
            int randomNum;

            //声明怪物数组
            Monster[] monsters = new Monster[10];

            //随机生成10个怪物 装载到怪物数组中
            for (int i = 0; i < monsters.Length; i++)
            {
                randomNum = r.Next(1, 101);

                //各百分之50的机会生成boss和哥布林
                if( randomNum < 50 )
                {
                    monsters[i] = new Boss();
                }
                else
                {
                    monsters[i] = new Goblin();
                }

            }

            //遍历10个怪物 执行对应子类的攻击方法
            for (int i = 0; i < monsters.Length; i++)
            {
                if( monsters[i] is Boss )
                {
                    (monsters[i] as Boss).Skill();
                }
                else
                {
                    (monsters[i] as Goblin).Atk();
                }
            }

            #endregion

            #region 练习题三

            //创建玩家
            Player p = new Player();

            //创建冲锋枪
            SubmachineGun s = new SubmachineGun();
            //拾取冲锋枪
            p.PickUp(s);

            //创建散弹枪
            ShotGun sg = new ShotGun();
            //拾取散弹枪
            p.PickUp(sg);

            #endregion
        }
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏