A S.O.L.I.D. Primer


Published on

A short primer on the solid principles

Published in: Technology
1 Like
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

A S.O.L.I.D. Primer

  1. 1. A ‘SOLID’ Primer<br />By KristofferRoupé<br />Jun 2009<br />
  2. 2. SingleResponsibilityPrinciple<br />THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE.<br />In the example the rectangle has 2 responsibilitiesand therefore it has 2 reasons to change.<br /><ul><li>If the Renderer has to change the way things are drawn, so does the Rectangle.
  3. 3. If the AreaComputer changes the way areas are computed, so does the Rectangle.</li></ul>  7 class Rectangle  8   area  9   draw 10 end 11  12 class Renderer 13   def render rectangle 14      rectangle.draw 15   end 16 end 17  18 class AreaComputer 19   def compute rectangle 20      rectangle.area 21   end 22 end<br />
  4. 4. Open/ClosedPrinciple<br />SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION BUT CLOSED FOR MODIFICATION. <br />It says that you should design modules that never change. <br />When requirements change, you extend the behavior of such modules by adding new code, not by changing old code that already works.<br /> 34 module Drawable 35   def draw  36   end 37 end 38  39 class Square 40   include Drawable 41 end 42  43 class Circle 44   include Drawable 45 end 46  47 def draw_all_shapes(shapes) 48   shapes.each { |shape| shape.draw } 49 end<br />
  5. 5. Liskov Substitution Principle<br />FUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT<br /> 56# simple violation of LSP 57 def draw_shape(shape) 58   shape.draw_circleif shape.method_defined? &apos;draw_cicle&apos; 59   shape.draw_rectangleif shape.method_defined? &apos;draw_rectangle&apos;  60 end<br />From this code it is quite obvious that the function has to know what kind of shape it is drawing. (Notice the ugly conditional statements)<br />
  6. 6. Liskov Substitution Principle cond.<br />A little more subtle violation of LSP. <br />You would expect that a rectangle should act as the methods and properties given, even if it is a derived class. <br />In this case the test would fail, hence breaking the contract of the parent.<br /> 62 # more subtle violation 63 class Rectangle 64   def height value 65     @height = value 66   end 67   def width value 68     @width = value 69   end 70 end 71  72 class Square &lt; Rectangle 73   def height value 74     @heigth = @width = value 75   end 76   def width value 77     height = value 78   end 79 end 80  81 describe Square do 82   it &quot;should not violate the contract of it&apos;s parent&quot; do 83     rectangle = Square.new 84     rectangle.height = 4 85     rectangle.width = 2 86     area = rectangle.height * rectangle.width 87     area.should be 8 88   end 89 end<br />
  7. 7. Interface Segregation Principle<br />CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USE<br />This principle deals with the disadvantages of “fat” interfaces.<br />Classes that have “fat” interfaces are classes whose interfaces are not cohesive. In other words, the interfaces of the class can be broken up into groups of member functions<br /> 95 class Door 96   def open 97   end 98   def close 99   end100   def is_open?101   end102 end103 104 class TimedDoor &lt; Door105   def door_time_out?106   end107 end108 109 class TimerClient110   def time_outid111   end  112 end113 114 class DoorTimerAdapter &lt; TimerClient115   def initialize timed_door116     @its_timed_door = timed_door117   end118   def time_out id119     @its_timed_door.door_time_out id120   end121 end<br />
  8. 8. Dependency Inversion Principle<br />HIGH LEVEL MODULES SHOULD NEVER DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND ON ABSTRACTIONS<br />ABSTRACTIONS SHOULD NEVER DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS<br /># A simple violation where button is directly dependent on lamp.129 class Lamp130   def turn_on!131   end132   def turn_off!133   end134 end135 136 class Button137   def initialize lamp138     @its_lamp = lamp139   end140   def detect!141     button_on = get_state142     @its_lamp.turn_on! if button_on143     @its_lamp.turn_off! unless button_on144   end145 end<br />
  9. 9. Dependency Inversion Principle<br />146 # A solution to that problem...147 module ButtonClient148  def turn_on!149  def turn_off!150 end151 152 class Button153   def initialize button_client154     @its_client = button_client155   end156   def detect157     button_on = get_state158     @its_client.turn_on! if button_on159     @its_client.turn_off! unless button_on160   end161   def get_state162   end163 end164 165 class Lamp &lt; ButtonClient166   def turn_on!167   end168   def turn_off!169   end170 end171 172 class ButtonImplementation &lt; Button173   def initialize button_client174   end175   def get_state176   end177 end<br />