28 should raiseerror 29 end 30 end 31 end Figure 1121 Line 12 contains a

28 should raiseerror 29 end 30 end 31 end figure 1121

This preview shows page 437 - 440 out of 517 pages.

28 should raise_error(...) 29 end 30 end 31 end Figure 11.21: Line 12 contains a Demeter violation: while it’s reasonable for MovieTheater to know about Moviegoer , it also knows about the implementation of Wallet , since it “reaches through” the wallet attribute to manipulate the wallet’s credit_balance . Also, we’re handling the problem of “not enough cash” in MovieTheater , even though logically it seems to belong in Wallet . Figure 11.21 shows an implementation of this behavior that contains a Demeter Principle violation. A
Image of page 437
problem arises if we ever change the implementation of Wallet —for example, if we change credit_balance to cash_balance , or add points_balance to allow moviegoers to accumulate PotatoPoints by becoming top reviewers. All of a sudden, the MovieTheater class, which is “twice removed” from Wallet , would have to change. Two design smells can tip us off to possible Demeter violations. One is inappropriate intimacy : the collect_money method manipulates the credit_balance attribute of Wallet directly, even though managing that attribute is the Wallet class’s responsibility. (When the same kind of inappropriate intimacy occurs repeatedly throughout a class, it’s sometimes called feature envy , because Moviegoer “wishes it had access to” the features managed by Wallet .) Another smell that arises in tests is the mock trainwreck , which occurs in lines 25–27 of Figure 11.21 : to test code that violates Demeter, we find ourselves setting up a “chain” of mocks that will be used when we call the method under test. Once again, delegation comes to the rescue. A simple improvement comes from delegating the credit_balance attribute, as Figure 11.22 (top) shows. But the best delegation is that in Figure 11.22 (bottom), since now the behavior of payment is entirely encapsulated within Wallet , as is the decision of when to raise an error for failed payments. 1 # Better: delegate credit_balance so MovieTheater only accesses Moviegoer 2 class Moviegoer 3 def credit_balance 4 self.wallet.credit_balance # delegation 5 end 6 end 7 class MovieTheater 8 def collect_money(moviegoer,amount) 9 if moviegoer.credit_balance >= amount 10 moviegoer.credit_balance -= due_amount 11 @collected_amount += due_amount 12 else 13 raise InsufficientFundsError 14 end 15 end 16 end 1 class Wallet 2 attr_reader :credit_balance # no longer attr_accessor! 3 def withdraw(amount) 4 raise InsufficientFundsError if amount > @credit_balance 5 @credit_balance -= amount 6 amount 7 end 8 end 9 class Moviegoer 10 # behavior delegation 11 def pay(amount) 12 wallet.withdraw(amount)
Image of page 438
13 end 14 end 15 class MovieTheater 16 def collect_money(moviegoer, amount) 17 @collected_amount += moviegoer.pay(amount) 18 end 19 end Figure 11.22: (Top) If Moviegoer delegates credit_balance to its wallet , MovieTheater no longer has to know about the implementation of Wallet . However, it may still be undesirable that the payment behavior (subtract payment from credit balance) is exposed to MovieTheater when it should really be the responsibility of Moviegoer or Wallet only. (Bottom) Delegating the behavior of payment, rather than the attributes through which it’s accomplished, solves the problem and eliminates the Demeter violation.
Image of page 439
Image of page 440

You've reached the end of your free preview.

Want to read all 517 pages?

  • Spring '19
  • Dr.Marcos

What students are saying

  • Left Quote Icon

    As a current student on this bumpy collegiate pathway, I stumbled upon Course Hero, where I can find study resources for nearly all my courses, get online help from tutors 24/7, and even share my old projects, papers, and lecture notes with other students.

    Student Picture

    Kiran Temple University Fox School of Business ‘17, Course Hero Intern

  • Left Quote Icon

    I cannot even describe how much Course Hero helped me this summer. It’s truly become something I can always rely on and help me. In the end, I was not only able to survive summer classes, but I was able to thrive thanks to Course Hero.

    Student Picture

    Dana University of Pennsylvania ‘17, Course Hero Intern

  • Left Quote Icon

    The ability to access any university’s resources through Course Hero proved invaluable in my case. I was behind on Tulane coursework and actually used UCLA’s materials to help me move forward and get everything together on time.

    Student Picture

    Jill Tulane University ‘16, Course Hero Intern

Stuck? We have tutors online 24/7 who can help you get unstuck.
A+ icon
Ask Expert Tutors You can ask You can ask You can ask (will expire )
Answers in as fast as 15 minutes
A+ icon
Ask Expert Tutors