Download presentation
Presentation is loading. Please wait.
1
Introduction to Software Design
In the “real world” we’re taught that design is pretty. Here we learn that design is about productivity.
2
Introduction to Design
Concepts and Diagnosis
3
Some things we’d like to be true
Mostly about easing CHANGE Easy to find what code to modify to add a feature …I only have to modify one class (in addition to writing the new code) …It’s easy to understand the class I have to change …My teammate can add another feature without us colliding or stopping working to talk …When I test my code, nobody else’s code needs to work Good software design gets us close to these ideals
4
Two Diagnostics for Good Design
Single Responsibility Principle (SRP) Each class should be responsible for one thing (capability, entity, computation, etc.) Can phrase this as “mind your own business” object do its own calculations object should not do calculations for another Easy to violate this because objects need to be connected to one another e.g., Events happen as part of Dates Don’t Repeat Yourself (DRY) Each computational idea should be expressed just once Violations often the result of cut-and-paste programming incomplete class (others have to do calculations for it, which also violates SRP) But also over-specialization of classes (class = object)
5
So OO Design is easy, right? Uh, no.
Tendency is to cram “related” functionality into existing classes, rather than creating new ones
6
SRP design has classes for “doers”
The four misplaced methods
7
So OO Design is easy, right? No. (pt II)
A related challenge is when two classes closely collaborate, like the iSwoon Date & Event classes
8
Example: iSwoon Repetition (violates DRY)
Note that only difference is the class of the object being manufactured. Remember that these would normally be in separate files. If one requires change, all do. Easy to miss one or change one incorrectly. validate is not only repetitive, but also a violation of SRP, although it’s hard to see here.
9
Example: iSwoon (continued)
This code violates SRP. Why? reuses the responsibility of which events go with which date it checks validity of events and also stores list of events Better phrasings: Date does not “validates-events itself” Changes to Event (like adding new event type) requires changing Date Date does not “validates events itself” Changes to Event (like adding new event type) requires changing Date
10
Example: iSwoon (continued)
Not just calling event method (that’s OK), but calculating on event data to derive event property Responsibility for Events (violates SRP) Here we can see the dual responsibility. We are comparing Event string names, not just calling Event methods. This means that Date has to know what these strings mean, how to compare them (whole string vs. prefix), etc. KNOWS TOO MUCH ABOUT EVENTS. Classes ideally interact purely through method calls. The fact that the comparison is outside the Event class is a red flag. Here we also again see repetitive, duplicated code. Cut-and-paste with an edit of the array initializer. Having a class to represent variation in data is WRONG. This is what objects are for, not classes. Classes are for variation in computation (different methods). So we should collapse these into a single class to achieve DRY. Also note that the only difference between subclasses is a constant data value
11
Repetition (violates DRY)
More repetition. At least at this point, there is no observable variation in computation, just data (but classes shouldn’t be used to capture variation in data). Collapse into a single class to achieve DRY. Also note that only difference in subclasses is a constant
12
Refactored iSwoon Design
No class for each date! Replaces 3 Event constructors We realized that the number of dates could be quite large, and having a new class for each one is ridiculous, esp. when the primary variation was data variation. Note that addEvent replaces the three methods from before (seeMovie, goToRestaurant, orderFlowers). Adding a new Date is now trivial – add 1!
13
Refactored iSwoon Design (cont’d)
No class for each event! Moved from Date to get SRP. Again, we collapse to one class because we are now handling the data variation with objects, not classes. Note that dateSupported(int) is the old validate(Event) from the Date classes. No magic strings, and the whole comparison is handled inside the class. I went even further than HFSD and decided that if an Event is OK on date K, then it’s OK on K+1. The fact is that high generality is often expensive to code (but not always). ARGUABLE THAT EVENT IS NOT SRP B/C OF DATE COMPARISON. Why “dateSupported” OK, but not “validateEvent”? In date? Finally, note that I’ve created some static FACTORY METHODS to help me create the objects I need to represent the old classes. These sort of methods might come about naturally from TDD, because the naked constructors are “too ugly” for a client to use and also threaten to violate SRP (the client would have to know the special strings and the first dates). “Factory” Methods keep Event details local
14
Refactored iSwoon Design (cont’d)
But now date functionality here! Why OK? Why is it OK to have dateSupported(int) in Event, but not validateEvent(Event) in Date? Because whether an Event is allowed is a property of the Event itself, not the Date The only thing that’s going to use a Date is an Event Dates are hard numbers, while events are flexible You wouldn’t have to change bit of code if you were to add another valid Event A. The Date class is really about an aggregation and ordering of Events within a date B. dateSupported is computing on an int, not a Date C. The dateSupported check is really the appropriateness of an *individual* Event for how mature the relationship is (again, the Date class mostly aggregating and ordering, not filtering)
15
Refactored iSwoon Design (cont’d)
But now date functionality here! Why OK? Why is it OK to have dateSupported(int) in Event, but not validateEvent(Event) in Date? My answers: dateSupported is checking the appropriateness of an individual Event for how mature the relationship is (not about the ordering of selected events) Said another way: Date class is about the ordering of selected Events for a date (not event validity) dateSupported is computing on an int, not a Date A. The Date class is really about an aggregation and ordering of Events within a date B. dateSupported is computing on an int, not a Date C. The dateSupported check is really the appropriateness of an *individual* Event for how mature the relationship is (again, the Date class mostly aggregating and ordering, not filtering)
16
People are Complicated
Consider this Java class, which is using good naming conventions to convey the meanings of the methods: class Person { public void rainedOn(); public boolean isWet(); public String getSpouseName(); public boolean isLeftHanded(); } Which methods are SRP? rainedOn(), isLeftHanded() isWet(), getSpouseName() isWet(), isLeftHanded() getSpouseName(), isLeftHanded() Answer: C D is tempting, but the fact that we’re getting the name from the Spouse object is the give-away: the Spouse should be asked for its name directly. (Later we’ll see that the spouse shouldn’t be stored in the Person class at all.)
17
Composition = “Has A” Consider the Java class: class Car { private Engine engine; private Transmission trans; … public start() throws BadDayException { for (int attempt=0; attempt < MAX_START; attempt++) engine.start(); } A Car is composed of a transmission and an engine. That is to say that a “Car has a Transmission and a Car has an Engine.” Composition is implemented via instance variables.
18
Sub Type = “Is A” Consider the Java classes: class Vehicle {
private Engine engine; … public start() throws BadDayException { for (int attempt=0; attempt < MAX_START; attempt++) engine.start(); } class Car extends Vehicle { private unsigned int passengerCount; public unsigned int getPassengerCount() { return passengers; } A Car is (necessarily) a type of Vehicle. That is to say that a car is a subtype of a vehicle. Subtypes can be implemented via Inheritance.
19
Interfaces (Pure Abstract Base Classes)
A form of operational subtype relationship Shares only interface, not implementation Appropriate when behaviors in common, but not because otherwise the same type. Enables interoperability, even among otherwise different types via interface reference. Avoid inheriting baggage, imposes desired disciple. Many types of things can be turned on and off. interface Switchable { public on(); public off(); } Names are often, but not necessarily, derived from verbs, e.g. Sortable, Iterable, Serializable, Cloneable, Runnable, etc.
20
Design Diagnosis Review
Three common mistakes in design TOO MUCH: Put all X-related functionality in class X (Automobile) TOO FRIENDLY: Blending of closely related classes (Date & Event) TOO LITTLE: Defining object-like classes (Date & Event) A few diagnostic techniques SRP: do the “____ itself” test on methods SRP: a change in one class causes change in another class DRY: repetitive code DRY: A “small” change requires many similar changes across methods or classes Constant Classes: Only diff. between classes is constants (same methods) “Is a” vs “Has a” vs “Can do” Test Determine if stand-alone, sub-type, or composite type If sub-type, determine if interface is shared, or implementation, and why
21
Design Repair For non-SRP functionality For DRY violation
Create additional classes, move there (Automobile) Move into existing classes (Date & Event) For DRY violation Create new method out of repetitive code, call it Merge repetitive, similar classes and encode differences with variables For “Has A” violation Replace inheritance with composition (Delegation pattern coming soon!) For “Is A” violation Use subtypes/inheritance to leverage commonality For “Can do”, but not “Is A” Use interface (pure abstract base class) to ensure no implementation leaks into common defintion
22
Take-Aways from Class Today
Object-oriented design is intuitive, but subtle Java is just a tool, does not guarantee good design (Just because I have an expensive camera does not make me a good photographer :) Easy to put functionality in wrong place, make classes too big, or make too small Possible to diagnosis and repair a design before or after the coding (may require both) SRP, DRY Is-A, Has-A, Can-Do Change in one class affects another (SRP) Small change affects multiple classes or methods Unfortunately, there are many kinds of design mistakes, and unique repairs for them
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.