里氏代换原则
定义:里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。
目的:里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
价值:里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
说实话,“任何基类可以出现的地方,子类一定可以出现”,这话太抽象了,我根本找不出另例子来证明,什么是符合这个原则的,什么是不符合这个原则的。
子类一定可以出现,从语言的基本要求角度来讲,这是必须的,面向对象中父类就是可以被子类替换的,那么这个要求针对的是啥?
是需求的层面,因为子类替换父类,在技术上一定是允许的,那么我们在设计上要加些什么样的限制来保证这一点呢。
一个一个的举例吧:
1.类作为函数的参数:函数(类)
这种情况,那对该函数的设计要求是:该函数不能处理个性的需求,也就是说,不应该去处理基类中某一类型所特有的机能,否则这个函数设计不合格。
对类的设计要求是:个性的东西一定要自己处理,不能公开。
2.类做未一个调用函数的对象:类.函数()
这种情况,对该函数的设计要求是,该函数必须处理的是共性的内容,个性的内容要用通过this指针去处理。
// 长方形 class Rectangle{
private: int h; int w; public: void setH(int value){
h = value; } void setW(int vaule){
w = vaule; } int getH(){
return h; } int getW(){
return w; } }; // 正方形 class Square:public Rectangle{
void set(int value){
setH(value); setW(value); } };
二.到这来应该是没有问题的,因为LSP是一个需求级别的设计要求。
现在假设有这么一个要求,保证长方形的宽度一定要大于高度。
函数如下:
class Clinet{
public: void setRectangle(Rectangle* r){
if(r->getW()<r->getH()){
r->setW(r->getH()+1); } } };
// 长方形 class Rectangle{
private: int h; int w; public: void setH(int value){
h = value; } void setW(int vaule){
w = vaule; } int getH(){
return h; } int getW(){
return w; } //设计变更 virtual void setRectangle(){
if(getW()<getH()){
setW(getH()+1); } } }; // 正方形 class Square:public Rectangle{
void set(int value){
setH(value); setW(value); } //设计变更 virtual void setRectangle(){
} }; class Clinet{
public: void setRectangle(Rectangle* r){
//设计变更 r->setRectangle(); } };
class Quadrilateral{
protected: int h; int w; public: virtual void setH(int value)=0; virtual void setW(int vaule)=0; virtual int getH()=0; virtual int getW()=0; }; // 长方形 class Rectangle: public Quadrilateral{
public: virtual void setH(int value){
h = value; } virtual void setW(int vaule){
w = vaule; } virtual int getH(){
return h; } virtual int getW(){
return w; } }; // 正方形 class Square:public Quadrilateral{
private: void setSide(int value){
h = w = value; } public: virtual void setH(int value){
setSide(value); } virtual void setW(int vaule){
setSide(vaule); } virtual int getH(){
return h; } virtual int getW(){
return w; } }; class Clinet{
public: void setRectangle(Rectangle* r){
if(r->getW()<r->getH()){
r->setW(r->getH()+1); } } }; //客户端调用 int main() {
cout<<"建造者模式演示\n"; //看代码不用考虑以下内容 int cin_a; cin>>cin_a; return 0; }
总结
设计无非就是解决共性和个性的问题,LSP做为一个原则,其实我们即使不学这个原则,也不一定不会遵守这个原则,因为如果你真的做了一个不符合这个原则的设计,那么运行马上就会遇到问题。
解决好共性和个性,就一定是一好的设计,一个符合各种设计原则的设计。
对于LSP这个原则,我其实一直都是理解的云里雾里的,直到现在才把这个东西具体化,所以,我觉得什么抽象的东西都试着举例说明,要不然你永远不会有一个清晰的思路。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/216414.html原文链接:https://javaforall.net
