{"id":472,"date":"2020-08-23T17:55:42","date_gmt":"2020-08-23T12:25:42","guid":{"rendered":"https:\/\/saurabhjain1537.wordpress.com\/?p=472"},"modified":"2025-02-27T07:46:42","modified_gmt":"2025-02-27T07:46:42","slug":"solid-principles-behavioral-subtyping","status":"publish","type":"post","link":"https:\/\/saurabhjain.dev\/?p=472","title":{"rendered":"SOLID Principles: Behavioral Subtyping"},"content":{"rendered":"\n<p>Also known as <strong>Liskov substitution principle<\/strong>, it states that a derived entity should be behavioral extension of the base entity and not just syntactical extension.<\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong>The Liskov Substitution Principle &#8220;L&#8221;<\/strong><\/p>\n\n\n\n<p>This is an often overlooked principle while defining class hierarchies. Base &amp; derived classes should have behavioral relation between them and Inheritance should not be applied just for the sake of reusing code. <\/p>\n\n\n\n<p>As per LSP, objects of Base class should be replaceable with objects of Derived class without any change in the behavior or correctness of the application.<\/p>\n\n\n\n<p>Inheritance signifies an Is-A relation between the derived class and the base class but at times, it can be misleading. Couple of classic examples:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li><strong>Square<\/strong> extends <strong>Rectangle<\/strong>: In basic geometric terms a square is a specific form of rectangle, so it might seem right for Square class to derive  from Rectangle.<ul><li>In object oriented design terms, a Rectangle has 2 sides but a Square has only 1.<\/li><li>When Square class extends Rectangle, it gets more variables than it needs and thus would need to do some work-around to achieve true behavior of a single side square.<\/li><li>Consider the following code snippet defying Behavioral Subtyping. <em>setHeight()<\/em> of Rectangle changes the value of variable <em>height <\/em>but <em>setHeight()<\/em> of Square changes both <em>height <\/em>&amp; <em>width<\/em>. If clients replaces a Rectangle object with a Square object, then they will observe (unexpectedly) that <em>setHeight()<\/em> changes both <em>height <\/em>&amp; <em>width<\/em>.<\/li><\/ul><\/li><\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>public class Rectangle {\n\n  protected int height;\n  protected int width;\n\n  public int getHeight() {\n    return height;\n  }\n\n  public void setHeight(int height) {\n    this.height = height;\n  }\n\n  public int getWidth() {\n    return width;\n  }\n\n  public void setWidth(int width) {\n    this.width = width;\n  }\n}\n\npublic class Square extends Rectangle {\n\n  @Override\n  public int getHeight() {\n    return super.getHeight();\n  }\n\n  @Override\n  public void setHeight(int height) {\n    super.setHeight(height);\n    super.setWidth(height);\n  }\n\n  @Override\n  public int getWidth() {\n    return super.getWidth();\n  }\n\n  @Override\n  public void setWidth(int width) {\n    super.setHeight(width);\n    super.setWidth(width);\n  }\n\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"2\"><li><strong>Stack <\/strong>extends <strong>Queue<\/strong>: Both of these data structures have <em>put()<\/em> and <em>get()<\/em> methods. The <em>put()<\/em> method for them is same because it adds an element at the end of the data structure. The <em>get()<\/em> method is different; it implements FIFO in case of Queue and LIFO in case of Stack.<ul><li>Defining <strong>Stack <\/strong>to extend <strong>Queue<\/strong> does provides code re usability but breaks the Liskov substitution principle because a Queue cannot be replaced with Stack without changing the underlying behavior.<\/li><li>A better class design would be something like the following. An abstract class <strong>AbstractCollection <\/strong>contains the common code of <em>put() <\/em>method and both <strong>Stack <\/strong>and <strong>Queue <\/strong>extend the abstract class to add concrete definition of <em>get()<\/em> method.<\/li><\/ul><\/li><\/ol>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"373\" height=\"236\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/08\/03-lsp-01-collection.png?w=373\" alt=\"\" class=\"wp-image-481\" \/><figcaption>Figure 1<\/figcaption><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>As per Wikipedia, Liskov substitution principle says &#8220;<em>if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program<\/em>&#8220;.<\/p>\n\n\n\n<p>In practice, applying this principle helps in deciding between Inheritance (Is-a) and Composition (Has-a) relation between classes.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Consider the following example of Rolling File Logger. <\/p>\n\n\n\n<p>The objective is to add log messages to a file and roll the file based on the size of file. The library needs to support another functionality of rolling the log file based on time interval.<\/p>\n\n\n\n<p>In this first approach (Figure 2) which defies Behavioral Subtyping, these two functionalities can be achieved by <strong>TimeRollingFileLogger <\/strong>extending <strong>SizeRollingFileLogger <\/strong>and overriding the method <em>isRolloverRequired()<\/em> which determines when to roll the log file.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"193\" height=\"303\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/08\/03-lsp-02-logger.png?w=193\" alt=\"\" class=\"wp-image-488\" \/><figcaption>Figure 2<\/figcaption><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>A better design is to separate the Rolling Strategy from the <strong>FileLogger<\/strong> like:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"633\" height=\"373\" src=\"https:\/\/saurabhjain.dev\/wp-content\/uploads\/2020\/08\/03-lsp-03-logger.png?w=633\" alt=\"\" class=\"wp-image-490\" \/><figcaption>Figure 3<\/figcaption><\/figure><\/div>\n\n\n\n<p>In the second approach of Figure-3, <strong>FileLogger <\/strong>has-a <strong>RollingStrategy <\/strong>and Interface <strong>RollingStrategy<\/strong> is implemented by three different concrete classes for three specific strategies viz None, SizeBased and TimeBased. <\/p>\n\n\n\n<p>The second approach better adheres to the behavioral relation between FileLogger and it&#8217;s rolling strategies in term of Object Oriented Design.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Conclusion<\/strong><\/p>\n\n\n\n<p>Behavioral Subtyping OR Liskov Substitution Principle helps in defining proper Object Oriented Design relation between classes by distinguishing Composition and Inheritance.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Also known as Liskov substitution principle, it states that a derived entity should be behavioral extension of the base entity and not just syntactical extension. The Liskov Substitution Principle &#8220;L&#8221; This is an often overlooked principle while defining class hierarchies. Base &amp; derived classes should have behavioral relation between them and Inheritance should not be &hellip; <a href=\"https:\/\/saurabhjain.dev\/?p=472\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">SOLID Principles: Behavioral Subtyping<\/span><\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[11,15,30,35,41,42,55],"class_list":["post-472","post","type-post","status-publish","format-standard","hentry","category-design","tag-behavioral-subtyping","tag-composition","tag-inheritance","tag-liskov-substitution-principle","tag-object-oriented-design","tag-object-oriented-programming","tag-solid-principles"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=\/wp\/v2\/posts\/472","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=472"}],"version-history":[{"count":1,"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=\/wp\/v2\/posts\/472\/revisions"}],"predecessor-version":[{"id":780,"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=\/wp\/v2\/posts\/472\/revisions\/780"}],"wp:attachment":[{"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=472"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=472"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/saurabhjain.dev\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=472"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}