Method Cohesion -- methods focus on one specific task, and doing it well.
Easier to understand methods if by themselves.
eg. int convertOzToMl(int ounces) // very specific, clear function
eg. int convert(int fromUnits, int toUnits, int fromAmount) // ambiguous and hard to use
Coding Cohesion -- smaller methods, which are called in combinations.
Instead of having one method do a lot of work, split it up into smaller methods.
If one method has to perform a number of different things, split those into smaller methods.
eg. Bad Coffee Model:
int modify(int action, int amount) // very hard to use, unclear
eg. Good Coffee Model:
void add(int amount) // easy to use, clear function
int remove(boolean all, int amount) // easy to use, but still uses a boolean
eg. Better Coffee Model:
void add(int amount) // easy to use, clear function
int releaseOneSip(int sipSize) // easy to use, clear function
int spillEntireContents() // Heh, poor guy.
Reducing Ambiguity -- methods should assume less about the user information
Methods cannot assume anything about what their user wants to modify. They should
only modify what the user expects them to modify.
eg. Adding Cream & Sugar
void add(int amountOfCoffee) // ambiguous, adds everything to coffee.
eg. Adding Cream OR Sugar!
void addCoffee(int amount) // easy to use, clear function
void addCream(int amount) // my value? amount = lots.
void addSugar(int amount) // same here. Black coffee is nasty.
High-Level Cohesion -- One method calling many smaller cohesive methods
One complex method is the sum of its parts, and performs one specific function: it
peforms a lot of cohesive small and specific parts to achieve a specific goal.
eg. That Regular Dude At Starbucks
private static final int kJoesCreamFraction = 30;
private static final int kJoesSugarFraction = 30;
void prepareCupForJoe(CoffeeCup cup, int amount) // very specific.
cup.addAmount(amount);
cup.addCream(amount/kJoesCreamFraction);
cup.addSugar(amount/kJoesSugarFraction);
This method is good because it doesn't ever influence the function of addAmount(),
addCream(), or addSugar for anybody else.
Avoid Method Explosion -- Do not use tons of methods when one makes sense
When methods need to be passed control, do not make separate methods for each
control case.
eg. Ordering Your Starbucks Coffee
void handleKeypress(char coffeeKey)
/* Not that specific, but we don't want 30 different methods for lattes/fraps/mochas/etc. */
Code Maintainability -- Tells other coders how your code works
Method names can be almost as useful as the javadocs.
int orderCoffee(CoffeeType type, int amount) // Confusing...
int orderCoffee(boolean isLatte, int amount) // Better, but let's just make it...
int orderLatte(int amount) // Nice!
Given all the coffee types at Starbucks, maybe the first one is better...it's the
programmer's judgement call
Summary of Code Cohesion
Maximize Cohesion
Avoid giving control data to methods
Balance cohesion with method explosion
Write easy to understand/maintain code
Using Interfaces:
Abstract Class vs. Interface
-- The age old question, which is appropriate when?
Abstract Classes
Useful when you want to define an object that is abstract.
If this object cannot exist as the object itself, that is an abstract class. For instance, Shape. (Oh, the
102 memories. Don't you remember the days when everything was simpler?)
Shapes don't exist by themselves. They actually only exist as other shapes, eg. Triangle, Circle,
Parallelogram, Polygon, etc.
To find an abstract class, ask yourself: "What kind of *blank* is it?" If you try to respond "It's a
*blank*" and it makes no sense, you have yourself an abstract class.
Something that an abstract
class could be is a subclass.
bad eg. "What kind of shape is it?" "It's a shape!" "...Yeah, that doesn't help me."
bad eg. "What kind of device is it?" "It's a device!" "*sigh*"
good eg. "What kind of device is it?" "It's a phone!" "...That doesn't LOOK like a phone.
Phones these days, what's gotten into them?
"
Abstract classes are useful for planned inheritance.
Interfaces
Useful if you want to define the methods of an object.
Interfaces define the function of objects they implement.
If this "object" defines the functions of another object, that is a good time for interfaces.
To find an interface, ask yourself: "Can this object do *blank*?" The "doing *blank*" part of that statement is your interface.
bad eg. "Can this music player play music?" "...Well, yes! It's what it does."
eg. "Can this iPod play music?" "Of course!"
eg. "Can this calculate play music?" "Anything 8 bits, bring it on!"
eg. "Can this phone play music?" "Are you kidding? It's got 5.1 surround sound!" "...Why
would you put that on a phone?!"
You've found your interface: MusicPlayer!
Interfaces are useful for design changes and adding functionality.
Using Interfaces
Provide method declarations for every function an object must have in order to implement the
interface. Each method must have no body.
eg. MusicPlayer
public void playMusic(String filename);
public void pauseMusic();
public void resumeMusic();
public String getCurrentSong();
public List getPlaylist();
Useful for classes that are all related, but do not extend the same classes.
eg. iPods and cellPhones are unrelated (for now!).
iPod extends MP3Player
cellPhone extends MobilePhone.
By implementing MusicPlayer, it means both these devices support playing music!
Who likes pizza? I love pizza myself, although when my order is messed up, I like it less. In fact, sometimes I absolutely can't stand it! Anchovies, ick!
Maybe it's because they were using the following method to take my order:
===
public void makePizza(boolean isVegetarian, boolean isVegan, Toppings[] customerToppings)
===
How do you even GET anchovies on my vegetarian pizza?! What the heck? With a method like this, it could happen, I guess...
Question #1: Make this cohesive! Let's make it so people can order Vegetarian, Vegan, Meat, and Everything. And, if you feel so inclined, whatever special pizza you like.
So, your pizza ordering software was so popular, now you own the place! And of course, you've wasted a ton of money on these pizza making machines, coded, of course, in Java.
Some of these machines make meat pizza better, some make vegetarian pizza better, vegan pizza needs its own special machine, and one machine does the house special.
In order to make your life simpler, you decide to code these machines to do at least some basic things.
Question #2: Write an interface for the pizza machines. They can all make dough, they can all put sauce on, and they can all put cheese (although the vegan substitute for cheese really doesn't count).
Resouces:
"What's a Method to Do?". Bill Venners. http://www.artima.com/designtechniques/cohesion9.html
"What is an Interface?". Sun Microsystems. http://java.sun.com/docs/books/tutorial/java/concepts/interface.html
"Abstract Classes vs. Interfaces". Tony Sintes. JavaWorld.com. http://www.javaworld.com/javaworld/javaqa/2001-04/03-qa-0420-abstract.html