Table of contents
- So what have we really done in the last part?
- New Changes
- Apply OO Principles(Step 2)
- Looking for problems
- 3 Important Tips
- Problem
- Solution
- Design once, design twice(Step 3)
- Let’s make sure Inventory.java is Really well-designed
- How easy is it to make this change to Rick's application?
- Problem
- Solution
- Chapter Recap
- References
So what have we really done in the last part?
We’ve gotten a lot closer to completing step 1 in building great software (Customer Happiness). We've solved Rick's search problem even though we made the app less fragile and it's not going to break so easily now.
New Changes
Rick's Customers ask for more choices, So Rick came up with a new requirement for his app:
- He wants the Search tool to return all the guitars that match his client’s specs, not just the first one in his inventory.
Let's change our code to satisfy our customer's change!
- First, we need to change the search method to return
List of objects
public List search(Guitar searchGuitar){ // C1 List matchingGuitars = new LinkedList(); // C2 for (Iterator it = guitars.iterator(); it.hasNext();){ Guitar guitar = (Guitar)it.next(); // Ignore serial number, price since they're unique. String builder = searchGuitar.getBuilder(); if ((builder != null) && (!builder.equals("")) && (!builder.equals(guitar.getBuilder()))) continue String model = searchGuitar.getModel(); if ((model != null) && (!model.equals("")) && (!model.equals(guitar.getModel()))) continue String type = searchGuitar.getType(); if ((type != null) && (!type.equals("")) && (!type.equals(guitar.getType()))) continue String backWood = searchGuitar.getBackWood(); if ((backWood != null) && (!backWood.equals("")) && (!backWood.equals(guitar.getBackWood()))) continue String topWood = searchGuitar.getTopWood(); if ((topWood != null) && (!topWood.equals("")) && (!topWood.equals(guitar.getTopWood()))) continue matchingGuitars.add(guitar); // C3 } return matchingGuitars; // C4 }
Also, don't forget to change our client code (it now receives list not single obj) 😉
public class FindGuitarTester {
public static void main(String[] args){
Guitar whatErinLikes = new Guitar(“”, 0, Builder.FENDER, “Stratocaster”, Type.ELECTRIC, Wood.ALDER, Wood.ALDER);
List matchingGuitars = inventory.search(whatErinLikes);
}
}
Now we need to make sure we’ve actually got those requirements handled by our code. Let’s test things out, and see if our app is working as Rick wants it to:
So now we have just finished the first step let's move to the next step(Customer Happy✅).
Apply OO Principles(Step 2)
Here we are at step 2 where we should take software that works, and make sure the way it's put together actually makes sense and is flexible to accept changes.
Looking for problems
Let's investigate the whole process of the search()
method
- Client provides their guitar preferences(clients only specify
general properties
, so they never supply a serial number or a price). - The Search tool looks through Rick's Inventory.
- Each Guitar is compared to the client's preferences(all
general properties
are compared to the client's preferences). - Rick's client is given a list of matching guitars.
So take a minute here to think if there is anything to improve before you continue reading!
Before I tell you what we should fix in our code let's learn some tips that might help you.
3 Important Tips
Objects should do only what their names indicate.
- if an object is name Jet, it should takeOff() and land(), but it shouldn't takeTicket() that's the job of another object and doesn't belong in jet.
Each object should represent a single concept.
- You don’t want objects serving double or triple duty.
- Avoid a Duck object that represents a real quacking duck, a yellow plastic duck.
- Unused properties are a dead giveaway.
- If you’ve got an object that is being used with no-value or null properties often, you’ve probably got an object doing more than one job.
- If you rarely have values for a certain property, why is that property part of the object?
Problem
You know, Rick’s clients really aren’t providing a Guitar object. I mean, they don’t actually give him a guitar to compare against his inventory.
Look here we don't really care if it's a guitar object or not we do care only about what specific things Rick’s clients are looking for.
Solution
So what about creating a new class that encapsulate
all these specs together in a single unit? Isn't that better than sending an entire Guitar object which makes no sense?
Before moving further I want to explain a word I said briefly.
Encapsulation is about breaking your app into logical parts and then keeping those parts separate. So just like you keep the data in your classes separate from the rest of your app’s behavior, we can keep the generic properties of a guitar separate from the actual Guitar object itself.
Anytime you see duplicate code, look for a place to encapsulate!
So let's describe our solution using the following steps:
- We need to create an object called
GuitarSpecs
that will wrap all Guitar Specs inside it. - We need to remove the duplicate code from the
Guitar
Object(Methods and Attributes). - We need to reference the
GuitarSpecs
object for eachGuitar
. - Update the Inventory class too (make the search tool compiles!).
You've learned a lot about writing great software and there's still more to go! let's end step 2 with some techniques we should always consider when we apply OO principles.
- Flexibility: Use it so that your software can change and grow without constant rework. it keeps your application from being fragile.
- Encapsulation: Use it to keep the parts of your code that stay the same separation from the parts that change; then it’s really easy to make changes to your code without breaking everything.
- Functionality: Without it, you’ll never actually make the customer happy. No matter how well-designed your application is, it's the thing that puts a smile on the customer’s face.
- Design Pattern: It's all about reuse and making sure you’re not trying to solve a problem that someone else has already figured out.
Design once, design twice(Step 3)
Once you’ve taken the first pass over your software and applied some basic OO principles, you’re ready to begin step 3
and take another look for enhancements, and this time make sure your software is not only flexible but easily reused and extended.
Let’s make sure Inventory.java is Really well-designed
As we know the only thing that's constant is change
we need to handle the case when Rick calls us back and asks for new changes it should be easy to add new features(make our code reusable, scalable, and extensible).
So in this step, we will focus on turning our classes into a reusable, extensible piece of software.
How easy is it to make this change to Rick's application?
Take a look at the class diagram for Rick’s application, and think about What you would need to do to add support for 12-string guitars?
- What properties and methods would you need to add and to what classes?
- What code would you need to change to allow Rick’s clients to search for 12-strings?
- How many classes did you have to modify to make this change?
Do you think Rick’s application is well-designed right now?
Problem
Let's walk through applying this change together and see how can we achieve this.
GuitarSpec Class
- We need to add a numStrings property.
- We need to add getNumStrings() method to return how many strings a guitar has.
Guitar Class
- We need to change the constructor of Guitar class since it takes in all the properties in GuitarSpec and creates a GuitarSpec object itself.
Inventory Class
- We need to change addGuitar() Method for sure to accept this new guitar specification.
- We need to change search() Method to handle this new specification too.
So that's the problem (Lots of modifications to accept only one new change).
We Shouldn't have to change the code in Guitar
and Inventory
to add a new property to the GuitarSpec
class.
Solution
As we can see all classes are interdependent. So what about more encapsulation?
Here are some steps we can follow to achieve this:
- Add a numStrings property and getNumStrings() method to GuitarSpec class.
- Modify the Guitar class so that properties of GuitarSpecs are encapsulated away from the constructor of the class
- Change the search() method in the Inventory class to delegate comparing the two GuitarSpec objects to the GuitarSpec class, instead of handling it directly.
Delegation is when an object needs to perform a certain task, and instead of doing that task directly, it asks another object to handle the task (or sometimes just a part of the task).
Congratulations! You’ve turned Rick’s broken inventory search tool into a well-designed piece of great software.
Chapter Recap
Let's recap how we got Rick's search tool working too well(And well designed too 😎).