Saturday, July 11, 2015

The Liskov Substitution Principle (LSP) - SOLID



https://miafish.wordpress.com/2015/01/09/liskov-substitution-principle/
what is Liskov Substitution principle
Child classes should never break the parent class’ type definitions. In other way, sub-types must be substitutable for their base types. As simple as that, a subclass should override the parent class’ methods in a way that does not break functionality from a client’s point of view.

The Liskov Substitution Principle (LSP)functions that use pointers to base classes must be able to use objects of derived classes without knowing it.
The Liskov Substitution Principle is a way of ensuring that inheritance is used correctly.
The idea here is that the subtypes must be replaceable for the super type references without affecting the program execution.

class Ostrich extends Bird{
07  fly(){
08    throw new UnsupportedOperationException();
09  }
10}
How do we fix such issues?
1class Bird{
2  public void eat(){}
3}
4class FlightBird extends Bird{
5  public void fly()()
6}
7class NonFlight extends Bird{}
How can we identify LSP violation?
Derived class may require less functionalities than the Base class, so some methods would be redundant.
http://www.infragistics.com/community/blogs/dhananjay_kumar/archive/2015/06/30/simplifying-the-liskov-substitution-principle-of-solid-in-c.aspx
Understanding the problem
public class Rectangle
  {
      public virtual int Height { getset; }
      public virtual int Width { getset; }
  }
public class Square : Rectangle
  {
      private int _height;
      private int _width;
      public override int Height
      {
          get
          {
              return _height;
          }
          set
          {
              _height = value;
              _width = value;
          }
      }
      public override int Width
      {
          get
          {
              return _width;
          }
          set
          {
             _width = value;
             _height = value;
          }
      }

  }
            Rectangle newRectangle = new Square();
            newRectangle.Height = 4;
            newRectangle.Width = 6;
            var result = AreaCalculator.CalculateArea(newRectangle);
            Assert.AreEqual(24, result); // fail
Solution:
public  interface class Shape
        {
        public  int Area();
        }
http://lassala.net/2010/11/04/a-good-example-of-liskov-substitution-principle/
NotImplemeneted, or UnsupportedException is bad.
http://www.objectmentor.com/resources/articles/lsp.pdf
http://www.tomdalling.com/blog/software-design/solid-class-design-the-liskov-substitution-principle/
定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。
定义2:所有引用基类的地方必须能透明地使用其子类的对象。
问题由来:有一功能P1,由类A完成。现需要将功能P1进行扩展,扩展后的功能为P,其中P由原有功能P1与新功能P2组成。新功能P由类A的子类B来完成,则子类B在完成新功能P2的同时,有可能会导致原有功能P1发生故障。
解决方案:当使用继承时,遵循里氏替换原则。类B继承类A时,除添加新的方法完成新增功能P2外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法。
         继承包含这样一层含义:父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。
        继承作为面向对象三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加了对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。
        里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:
  • 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
  • 子类中可以增加自己特有的方法。
  • 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
        看上去很不可思议,因为我们会发现在自己编程中常常会违反里氏替换原则,程序照样跑的好好的。所以大家都会产生这样的疑问,假如我非要不遵循里氏替换原则会有什么后果?
        后果就是:你写的代码出问题的几率将会大大增加。

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts