Unity设计模式---里氏替换原则---4

33 阅读2分钟

里氏替换:所有引用(父类)基类的地方必须能透明地使用其子类的对象。

里氏替换原则:在软件中如果能够使用基类对象,那么一定能够使用其子类对象。将基类都替换成它的子类,程序不会出现错误和异常,反过来则不成立。

里氏替换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来定义对象,而在运行时再确定子类类型,用子类对象替换父类对象。

由于里氏替换原则,才使得开闭成为了可能。


namespace 里氏替换原则
{
    public abstract class AbstractGun 
    {
        public abstract void Shoot();
    }

    public class HandGun : AbstractGun
    {
        public override void Shoot()
        {
            Console.WriteLine("手枪射击");
        }
    }

    public class Rifle : AbstractGun
    {
        public override void Shoot()
        {
            Console.WriteLine("步枪射击");
        }
    }

    public class Machinegun : AbstractGun
    {
        public override void Shoot()
        {
            Console.WriteLine("机枪射击");
        }
    }

    public class ToyGun : AbstractGun
    {
        public override void Shoot()
        {
            Console.WriteLine("玩具射击");
        }
    }

    public class G3 : Rifle
    {
        public  void ZoomOut()
        {
            Console.WriteLine("望远镜杀敌人");
        }
        public override void Shoot()
        {
            Console.WriteLine("G3射击");
        }
    }

    public class Snipper
    {
        public void KillEnemy(G3 g3)
        { 
            g3.ZoomOut();
            g3.Shoot();
        }
    }
    public class Solider
    {
        public void KillEnemy(AbstractGun gun)
        {
            Console.WriteLine("战士开始战斗");
            gun.Shoot();
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            Solider hero= new Solider();
            //里氏替换
            hero.KillEnemy(new ToyGun());
            hero.KillEnemy(new Rifle());

            Snipper hero01=new Snipper();

            //里氏替换
            Rifle rifle=new G3();
            hero01.KillEnemy((G3)rifle);
            Console.Read();
        }
    }
}

违反里氏替换原则案例:

 public class A
    {
        public virtual int Func(int x, int y)
        { 
            return x + y;
        }
    }

    public class B : A 
    { 
        public override int Func(int x, int y) 
        {  
            return x - y;  //违反了里氏替换原则,直接重写了父类的Func虚拟方法,
            //引用父类的地方并不能透明的使用子类的对象。
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            A a=new B();
            Console.WriteLine("a+b="+a.Func(10,5));
            Console.Read();
        }
    }

当要拓展父类服务时的案例:


namespace 里氏替换原则3
{
    internal class Program
    {
        public class A 
        { 
            public int Func(int x,int y)

            { return x + y; }
        }

        public class B:A 
        {
            public int Func1(int x, int y)
            { 
                return x - y;
            }
        }
        static void Main(string[] args)
        {
            //当要拓展类功能的时候,不要去重写父类提供的服务,而是在子类中直接添加新的服务
            B b = new B();
            Console.WriteLine("1-2="+b.Func1(1,2));
            Console.Read();
        }
    }
}

里氏替换的最后案例:


namespace 里氏替换4
{
    /// <summary>
    /// 矩形类
    /// </summary>
    public class Rectangle
    {
        int height;
        int width;

        /// <summary>
        /// 获取长度
        /// </summary>
        /// <returns>返回矩形长度值</returns>
        public int GetHeight() { return height; }

        /// <summary>
        /// 设置长度
        /// </summary>
        /// <param name="height">传入长度值</param>
        public void SetHeight(int height)
        {
            this.height = height;
        }

        /// <summary>
        /// 获取宽度值
        /// </summary>
        /// <returns>返回矩形宽度值</returns>
        public int GetWidth() { return width; }

        /// <summary>
        /// 设置宽度值
        /// </summary>
        /// <param name="width">传入宽度值</param>
        public void SetWidth(int width)
        {
            this.width = width;
        }

    }

    public class Square : Rectangle
    {
        int size;
        public int GetSize() { return size; }
        public void SetSize(int size)
        { 
            this.size = size;
        }
    }
    internal class Program
    {
     
        //调整长方形的宽度值,让长方形的边长调整比height更长,如果传进去的实际上是一个正方形,那么程序会调用很多次
        public static void TestRec(Rectangle rec)
        {
            int i = 0;
            while (rec.GetWidth()<=rec.GetHeight()) 
            { 
                rec.SetWidth(rec.GetWidth()+1);
                Console.WriteLine("循环的次数:"+i++);
            }
        }


        static void Main(string[] args)
        {
            Rectangle rec= new Square();
            rec.SetWidth(5);
            rec.SetHeight(10);
            TestRec(rec);
            Console.ReadLine();
        }
    }
}