Oop 为什么创建对象时使用其基本对象作为其类型,而创建对象时使用特定类型的对象
我的问题很难翻译成英语,所以我会尽力的 在阅读一篇关于Liskov替换原理的文章时,我发现这个例子非常常见,可以说明LSP的重要性 有一个AreaCalculator类、一个Shape类和一个Rectangle类,该代码显示了在创建一个newrectangle作为其基础类但使用和子类型(如Rectangle newrectangle=new Square)时调用AreaCalculator的问题 我的问题是,如果我可以使用特定类型,为什么我要使用它的基类作为它的类型来创建一个对象?好处是什么Oop 为什么创建对象时使用其基本对象作为其类型,而创建对象时使用特定类型的对象,oop,Oop,我的问题很难翻译成英语,所以我会尽力的 在阅读一篇关于Liskov替换原理的文章时,我发现这个例子非常常见,可以说明LSP的重要性 有一个AreaCalculator类、一个Shape类和一个Rectangle类,该代码显示了在创建一个newrectangle作为其基础类但使用和子类型(如Rectangle newrectangle=new Square)时调用AreaCalculator的问题 我的问题是,如果我可以使用特定类型,为什么我要使用它的基类作为它的类型来创建一个对象?好处是什么 R
Rectangle newRectangle = new Square(); vs `Square newRectangle = new Square();`
此方法返回一个错误的平方面积
public void TwentyFor4X5RectangleFromSquare()
{
Rectangle newRectangle = new Square();
newRectangle.Width = 4;
newRectangle.Height = 5;
Assert.AreEqual(20, AreaCalculator.CalculateArea(newRectangle));
}
public class AreaCalculator
{
public static int CalculateArea(Rectangle r)
{
return r.Height * r.Width;
}
public static int CalculateArea(Square s)
{
return s.Height * s.Height;
}
}
public class Rectangle
{
public virtual int Height { get; set; }
public virtual int Width { get; set; }
}
public class Square : Rectangle
{
private int _height;
private int _width;
public override int Width
{
get { return _width; }
set
{
_width = value;
_height = value;
}
}
public override int Height
{
get { return _height; }
set
{
_width = value;
_height = value;
}
}
}
得到错误答案的原因是,设置正方形对象的宽度或高度会同时设置正方形的宽度和高度 所以当你设定
newRectangle.Width = 4
newRectangle.Height = 5
然后你有一个4x4正方形,然后你设置
newRectangle.Width = 4
newRectangle.Height = 5
你有一个5x5的正方形
给你一个25的面积
如果删除此方法,则可以使用一个示例来说明为什么要将类设置为它的基类
public static int CalculateArea(Square s)
{
return s.Height * s.Height;
}
您仍然可以计算正方形的面积,这是因为您的代码是根据合同而不是特定类型编写的。其中,所创建的接口是您建立的合同的一部分 例如,这个例子来自jeremy clarks的接口C 当您有一个用于人员的存储库,该存储库使用一个类person的实例创建人员并返回一个人员数组时,如下所示
Class PeopleRepository
{
public Person[] GetPeople()
{...}
}
如果您创建一个特定的类型,您可以这样做
PeopleRepository pr = new PeopleRepository()
Person[] people = pr.GetPeople()
foreach(var in people)
//Do something
如果在repository类中更改了GetPeople的实现以返回列表和数组,那么上面的代码将无法工作。但是,如果您使用接口,它将工作例如
IEnumerable people;
people = = pr.GetPeople()
foreach(var in people)
//Do something
正如amit所说,代码将更容易重构和维护重构要容易得多。强制您使用所需内容,而不是临时实现,从而为您提供更好的代码。允许不知道实际类型是什么,只有基类型对方法非常有用arguments@amit你知道我可以用来了解更多的文档吗。我还是不明白这有什么好处。@gorilla谢谢。我知道我得到了错误的答案,我的问题是,为什么更好地使用它的基类型作为its类型来创建对象,而不是我想在特定代码中使用的类型。