1 / 22

Design Points - Law of Demeter

Design Points - Law of Demeter. Stéphane Ducasse --- 2005. About Coupling. Why coupled classes is fragile design? Law of Demeter Thoughts about accessor use. Coupling hampers. Reuse I cannot reuse this component in another application Substitution

leahh
Download Presentation

Design Points - Law of Demeter

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Design Points - Law of Demeter Stéphane Ducasse --- 2005

  2. About Coupling • Why coupled classes is fragile design? • Law of Demeter • Thoughts about accessor use

  3. Coupling hampers... • Reuse • I cannot reuse this component in another application • Substitution • I cannot substitute easily this component for another one • Encapsulation • When a far away change happens, I get impacted

  4. The Core of the Problem

  5. The Law of Demeter • You should only send messages to: • an argument passed to you • instance variables • an object you create • self, super • your class • Avoid global variables • Avoid objects returned from message sends other than self

  6. Correct Messages • someMethod: aParameter • self foo. • super someMethod: aParameter. • self class foo. • self instVarOne foo. • instVarOne foo. • aParameter foo. • thing := Thing new. • thing foo

  7. In other words • Only talk to your immediate friends. • In other words: • You can play with yourself. (this.method()) • You can play with your own toys (but you can't take them apart). (field.method(), field.getX()) • You can play with toys that were given to you. (arg.method()) • And you can play with toys you've made yourself. (A a = new A(); a.method())

  8. Halt!

  9. To not skip your intermediate

  10. Solution

  11. Transformation

  12. Heuristic of Demeter • Not a law • Know when you can bend it or not apply it • Encapsulating collections may produce large interfaces so not applying the LoD may help.

  13. Collections • Object subclass: #A • instVar: myCollection • A>>do: aBlock • myCollection do: aBlock • A>>collect: aBlock • ^ myCollection collect: aBlock • A>>select: aBlock • ^ myCollection select: aBlock • A>>detect: aBlock • ^ myCollection detect: aBlock • A>>isEmpty • ^ myCollection isEmpty • …………………

  14. About the Use of Accessors • Some schools say: “Access instance variables using methods” • In such a case • Be consistent inside a class, do not mix direct access and accessor use • Think accessors as protected methods (not invoked by clients) • in ST: put them in accessing only when public

  15. Accessors • Accessors are good for lazy initialization • Scheduler>>tasks • tasks isNil ifTrue: [task := ...]. • ^ tasks • BUT accessors methods should be Protected by default at least at the beginning

  16. Example • Scheduler>>initialize • self tasks: OrderedCollection new. • Scheduler>>tasks • ^ tasks • But now everybody can tweak the tasks!

  17. Accessors open Encapsulation • The fact that accessors are methods doesn’t support a good data encapsulation. • You could be tempted to write in a client: • ScheduledView>>addTaskButton • ... • model tasks add: newTask • What’s happen if we change the representation of tasks?

  18. Tasks • If tasks is now an array, it will break • Take care about the coupling between your objects and provide a good interface! • Schedule>>addTask: aTask • tasks add: aTask • ScheduledView>>addTaskButton • ... • model addTask: newTask

  19. About Copy Accessor • Should I copy the structure? • Scheduler>>tasks • ^ tasks copy • But then the clients can get confused... • Scheduler uniqueInstance tasks removeFirst • and nothing happens!

  20. You will read code • Code that others wrote • Code that you wrote and forgot

  21. Use intention revealing names • Probably Better • Scheduler>>taskCopy or copiedTasks • “returns a copy of the pending tasks” • ^ task copy

  22. Provide a Complete Interface • Workstation>>accept: aPacket • aPacket addressee = self name • … • It is the responsibility of an object to offer a complete interface that protects itself from client intrusion. • Shift the responsibility to the Packet object • Packet>>isAddressedTo: aNode • ^ addressee = aNode name • Workstation>>accept: aPacket • (aPacket isAddressedTo: self) • ifTrue:[ Transcript show: 'A packet is accepted by the Workstation ', self name asString] • ifFalse: [super accept: aPacket]

More Related