Download presentation
Presentation is loading. Please wait.
1
HFOOAD Chapter 5 Interlude
OO Catastrophe! We’ll look at the O-O techniques discussed in the brief interlude that comes in the middle of chapter 5 here. You should be thinking about O-O principles all the time (at least while you’re developing software).
2
Watch it. The answer is a bit tricky
Watch it. The answer is a bit tricky. The book offers one answer, but it’s a little bit more specific than you need to be. Can you think of a second answer as well?
3
Two possible answers Interface Defines behavior Cannot be instantiated
Contract Cannot be instantiated A class can implement multiple interfaces In languages that support interfaces Abstract class Defines behavior Can have implementation code Cannot be instantiated A class can inherit from a single abstract class Unless the language supports multiple inheritance
4
Avoid repeating code with abstract classes
How do I know when to use an interface and when to use an abstract class? If (almost) all classes implementing the behavior would have the same code, then you can use an abstract class to implement it. Avoid repeating code with abstract classes You probably get the idea by now that duplicating code is not a good thing. So, you want to avoid it whenever possible. Some people are really fanatical about it, which isn’t a bad thing. An abstract class can be very useful for reducing duplicate code, but you should be sure that it’s warranted before using one. Often, even with abstract classes, we create an interface for it. Interfaces define the contract of the behavior by expressing the signature of the method and its return type. Program to interfaces
6
ENCAPSULATION Isn’t encapsulation just about hiding implementation?
This is a very good question. Certainly hiding how we implement behavior makes it easy to change the implementation—as long as it obeys the contract set up by the interface. But it’s more than that. We want the behavior that we encapsulate to be cohesive. That is, we want it all to relate to one primary thing. We need to look at our code to see where changes are possible and encapsulate those areas as well. This will be come clearer as we go on, but let’s look at how we might think about using encapsulation to arrive at a good solution.
7
Solution 1 We have a good idea of what a painter’s behavior is and we understand that there is a variation in the way a painter paints, depending upon the painter’s style. We might start by envisioning a design like this one. We encapsulate the behavior in an abstract base class, Painter. Now all painters will prepare their easels the same way and clean their brushes the same. The difference in their behavior is in the paint method so we make that an abstract method that will be implemented in each subclass. Now if we add a new painting style, we need to add a new subclass. We’ve seen examples of this approach already with Rick’s application. Yet, it’s not quite as good as we’d like.
8
Solution 2 This solution is very similar to the solution on p. 226 of the text. We’ve modified it in four ways here. This was done after spending more time thinking about the solution in the book. (Designs evolve. Even when writing a book we have time constraints and need to put in a solution that’s good enough to make the publishing deadline.) The changes and rationale for them are: We changed the name of PaintStyle to PaintAction. This represents more the intention of the class’s purpose. It seems like a paint style is not responsible for actually painting, but a paint action is one that we would expect to perform the painting. We made PaintAction an interface. Since there is no common code for painting—each style is unique—so making PaintAction an abstract class does not express the design as well as it might. Since PaintAction is an interface, we changed the generalization connectors that connect the interface to the implementing classes. This is the UML notation to show how a class “realizes” an interface. The dashed line versus the solid line is the distinguishing difference. We kept the paint method in the Painter class. Rather than requiring getting the paint style from the painter and then telling the style to paint (which is what would be needed in the solution in the book), we tell the Painter object to paint. The paint method in the Painter class will simply pas the request on to the paint method in the PaintAction delegate. If you think about this, what we’ve done is further encapsulate the implementation of how painting is performed. The client of the Painter doesn’t know if the Painter object is really doing the painting itself or not—nor should it.
9
Prefer delegation over inheritance
What we’ve done to arrive at the better solution is to “delegate” the responsibility for the variable behavior to a separate object. (We’ll see why shortly.) This provides a more flexible solution which makes it easier to add a new style of painter to the system by just adding a new class that implements the PaintAction interface.
11
Change Change Change Change
Manage change … Change Change Change OK, here’s your new mantra. Keep change in mind all the time as you design software solutions. Managing change is the single most important thing you need to address in order to build systems that are flexible and maintainable. We’ve said this before and you can be sure that we’ll be saying it again as we proceed. Encapsulation and making our classes cohesive are great ways of managing change. Change
12
Final Catastrophe challenge
Look at the class diagram here. This is a pretty contrived example that’s mainly structural, but it will let you flex your new OOAD muscles and apply what we’ve talked about here. How ould you change the design to make it more flexible? You don’t have to make the changes (unless you want to), but you do need to describe how you would do it.
13
Our solution This is certainly not the only answer, but we think it’s a pretty good one.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.