里氏替换:所有引用(父类)基类的地方必须能透明地使用其子类的对象。
里氏替换原则:在软件中如果能够使用基类对象,那么一定能够使用其子类对象。将基类都替换成它的子类,程序不会出现错误和异常,反过来则不成立。
里氏替换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来定义对象,而在运行时再确定子类类型,用子类对象替换父类对象。
由于里氏替换原则,才使得开闭成为了可能。
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();
}
}
}