際際滷

際際滷Share a Scribd company logo
A SOLID PrimerBy KristofferRoup辿Jun 2009
SingleResponsibilityPrincipleTHERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE.In the example the rectangle has 2 responsibilitiesand therefore it has 2 reasons to change.If the Renderer has to change the way things are drawn, so does the Rectangle.
If the AreaComputer changes the way areas are computed, so does the Rectangle.7 classRectangle8 area9 draw10 end11 12 classRenderer13 defrenderrectangle14 rectangle.draw15 end16 end17 18 classAreaComputer19 defcomputerectangle20 rectangle.area21 end22 end
Open/ClosedPrincipleSOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION BUT CLOSED FOR MODIFICATION. It says that you should design modules that never change. When requirements change, you extend the behavior of such modules by adding new code, not by changing old code that already works.34 moduleDrawable35 defdraw36 end37 end38 39 classSquare40 includeDrawable41 end42 43 classCircle44 includeDrawable45 end46 47 defdraw_all_shapes(shapes)48 shapes.each { |shape|shape.draw }49 end
Liskov Substitution PrincipleFUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT56# simple violation of LSP57 defdraw_shape(shape)58 shape.draw_circleifshape.method_defined? 'draw_cicle'59 shape.draw_rectangleifshape.method_defined? 'draw_rectangle'60 endFrom this code it is quite obvious that the function has to know what kind of shape it is drawing. (Notice the ugly conditional statements)
Liskov Substitution Principle cond.A little more subtle violation of LSP. You would expect that a rectangle should act as the methods and properties given, even if it is a derived class. In this case the test would fail, hence breaking the contract of the parent.62 # more subtle violation63 classRectangle64 defheightvalue65 @height= value66 end67 defwidthvalue68 @width= value69 end70 end71 72 classSquare< Rectangle73 defheightvalue74 @heigth= @width= value75 end76 defwidthvalue77 height = value78 end79 end80 81 describe Squaredo82 it "should not violate the contract of it's parent"do83 rectangle = Square.new84 rectangle.height = 485 rectangle.width = 286 area = rectangle.height * rectangle.width87 area.should be 888 end89 end
Interface Segregation PrincipleCLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USEThis principle deals with the disadvantages of fat interfaces.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 functions95 classDoor96 defopen97 end98 defclose99 end100 defis_open?101 end102 end103 104 classTimedDoor< Door105 defdoor_time_out?106 end107 end108 109 classTimerClient110 deftime_outid111 end112 end113 114 classDoorTimerAdapter< TimerClient115 definitializetimed_door116 @its_timed_door= timed_door117 end118 deftime_outid119 @its_timed_door.door_time_out id120 end121 end
Dependency Inversion PrincipleHIGH LEVEL MODULES SHOULD NEVER DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND ON ABSTRACTIONSABSTRACTIONS SHOULD NEVER DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS# A simple violation where button is directly dependent on lamp.129 classLamp130 defturn_on!131 end132 defturn_off!133 end134 end135 136 classButton137 definitializelamp138 @its_lamp= lamp139 end140 defdetect!141 button_on = get_state142 @its_lamp.turn_on! ifbutton_on143 @its_lamp.turn_off! unlessbutton_on144 end145 end

More Related Content

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

  • 1. A SOLID PrimerBy KristofferRoup辿Jun 2009
  • 2. SingleResponsibilityPrincipleTHERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE.In the example the rectangle has 2 responsibilitiesand therefore it has 2 reasons to change.If the Renderer has to change the way things are drawn, so does the Rectangle.
  • 3. If the AreaComputer changes the way areas are computed, so does the Rectangle.7 classRectangle8 area9 draw10 end11 12 classRenderer13 defrenderrectangle14 rectangle.draw15 end16 end17 18 classAreaComputer19 defcomputerectangle20 rectangle.area21 end22 end
  • 4. Open/ClosedPrincipleSOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION BUT CLOSED FOR MODIFICATION. It says that you should design modules that never change. When requirements change, you extend the behavior of such modules by adding new code, not by changing old code that already works.34 moduleDrawable35 defdraw36 end37 end38 39 classSquare40 includeDrawable41 end42 43 classCircle44 includeDrawable45 end46 47 defdraw_all_shapes(shapes)48 shapes.each { |shape|shape.draw }49 end
  • 5. Liskov Substitution PrincipleFUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT56# simple violation of LSP57 defdraw_shape(shape)58 shape.draw_circleifshape.method_defined? 'draw_cicle'59 shape.draw_rectangleifshape.method_defined? 'draw_rectangle'60 endFrom this code it is quite obvious that the function has to know what kind of shape it is drawing. (Notice the ugly conditional statements)
  • 6. Liskov Substitution Principle cond.A little more subtle violation of LSP. You would expect that a rectangle should act as the methods and properties given, even if it is a derived class. In this case the test would fail, hence breaking the contract of the parent.62 # more subtle violation63 classRectangle64 defheightvalue65 @height= value66 end67 defwidthvalue68 @width= value69 end70 end71 72 classSquare< Rectangle73 defheightvalue74 @heigth= @width= value75 end76 defwidthvalue77 height = value78 end79 end80 81 describe Squaredo82 it "should not violate the contract of it's parent"do83 rectangle = Square.new84 rectangle.height = 485 rectangle.width = 286 area = rectangle.height * rectangle.width87 area.should be 888 end89 end
  • 7. Interface Segregation PrincipleCLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USEThis principle deals with the disadvantages of fat interfaces.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 functions95 classDoor96 defopen97 end98 defclose99 end100 defis_open?101 end102 end103 104 classTimedDoor< Door105 defdoor_time_out?106 end107 end108 109 classTimerClient110 deftime_outid111 end112 end113 114 classDoorTimerAdapter< TimerClient115 definitializetimed_door116 @its_timed_door= timed_door117 end118 deftime_outid119 @its_timed_door.door_time_out id120 end121 end
  • 8. Dependency Inversion PrincipleHIGH LEVEL MODULES SHOULD NEVER DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND ON ABSTRACTIONSABSTRACTIONS SHOULD NEVER DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS# A simple violation where button is directly dependent on lamp.129 classLamp130 defturn_on!131 end132 defturn_off!133 end134 end135 136 classButton137 definitializelamp138 @its_lamp= lamp139 end140 defdetect!141 button_on = get_state142 @its_lamp.turn_on! ifbutton_on143 @its_lamp.turn_off! unlessbutton_on144 end145 end
  • 9. Dependency Inversion Principle146 # A solution to that problem...147 moduleButtonClient148 defturn_on!149 defturn_off!150 end151 152 classButton153 definitializebutton_client154 @its_client= button_client155 end156 defdetect157 button_on = get_state158 @its_client.turn_on! ifbutton_on159 @its_client.turn_off! unlessbutton_on160 end161 defget_state162 end163 end164 165 classLamp< ButtonClient166 defturn_on!167 end168 defturn_off!169 end170 end171 172 classButtonImplementation< Button173 definitializebutton_client174 end175 defget_state176 end177 end