0% found this document useful (0 votes)
20 views68 pages

Object-Oriented Design Heuristics: Alexandre Bergel Abergel@dcc - Uchile.cl 24/05/2011

This document discusses object-oriented design heuristics and principles. It provides examples of poor design from real code, such as exposing public fields instead of using accessors, god classes that do too much, and model classes depending on interface classes. The document emphasizes principles like hiding data, minimizing interfaces, capturing single abstractions, separating model and interface, and avoiding god classes. Visualizations are used to illustrate concepts like system complexity and class internals.

Uploaded by

Thendral
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views68 pages

Object-Oriented Design Heuristics: Alexandre Bergel Abergel@dcc - Uchile.cl 24/05/2011

This document discusses object-oriented design heuristics and principles. It provides examples of poor design from real code, such as exposing public fields instead of using accessors, god classes that do too much, and model classes depending on interface classes. The document emphasizes principles like hiding data, minimizing interfaces, capturing single abstractions, separating model and interface, and avoiding god classes. Visualizations are used to illustrate concepts like system complexity and class internals.

Uploaded by

Thendral
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 68

Object-Oriented

Design Heuristics
Alexandre Bergel
abergel@dcc.uchile.cl
24/05/2011
Source

Book from Arthur J. Riel


Addison-Wesley Professional (May 10, 1996)

978-0201633856

Java 1.6

Pharo 1.0
Goal of this lecture

Provide useful and simple programming “rules”


Insight into object-oriented design improvement
Intended to
Increase the readability and the quality of your code

Facilitate software maintenance


Goal of this lecture

To make you better programmers and responsible


engineers
This lecture provides good hints to not make people
throw stones at you when they will look at your code
Class a
Classes and Objects
Classes and Objects

The building blocks of the object-oriented paradigm


An object will always have four important facets
its own identify (e.g., its address in memory)

the attributes of its class (usually static) and values for those
attributes (usually dynamic)

the behavior of its class (the implementor’s view)

the published interface (the user’s view)


All data should be hidden within its class
public class DefaultCaret extends Rectangle implements Caret,
FocusListener, MouseListener, MouseMotionListener {
...
int updatePolicy = UPDATE_WHEN_ON_EDT;
boolean visible;
boolean active;
int dot;
int mark;
Object selectionTag;
boolean selectionVisible;
Timer flasher;
Point magicCaretPosition;
transient Position.Bias dotBias;
transient Position.Bias markBias;
boolean dotLTR;
boolean markLTR;
transient Handler handler = new Handler();
transient private int[] flagXPoints = new int[3];
transient private int[] flagYPoints = new int[3];
private transient NavigationFilter.FilterBypass filterBypass;
static private transient Action selectWord = null;
static private transient Action selectLine = null;
...
}

Piece of code extracted from the JDK 1.6. The class DefaultCaret belongs to the package
javax.swing.text. It contains 15 public attributes
Handler

DefaultCaret

Class blueprint [Lanza 2003]

We will make heavy use of visualization along the semester. Visualizing software is a very handy
and intuitive mechanism for getting a quantitative and qualitative impression about a system.

Class blueprint is a visualization that shows class internal. A class is represented as a box. Each
box is composed of 5 part. Each part correspond to some particular elements that composes the
class. From left to right: constructors, public methods, private methods, variable accessors and
mutators (get and set methods), attributes.

Blue edges represent methods invocations. Cyan edges represent variable accesses.
Access to public variables

Handler

DefaultCaret

Class blueprint [Lanza 2003]

The class DefaultCaret contains 15 public attributes. These attributes are accessed by other
classes. Handler for example. This shows a poor programming style. Never make field public or
package visible.

One may argue that for optimization reason, it may be preferable to have public variables instead
of accessors. It was true some time ago when virtual machines and compiler were not that
sophisticated. Today, making variable public is hardly considered as an efficient way to optimize
your program.
How to hide data?

Visibility of variables should be set to private or


protected
Define accessors and mutators when necessary
Minimize the number of messages in the protocol of a class
number of
variables

number of number of
lines of code methods

System complexity [Lanza 2003]

We can see another visualization, called System complexity. This visualization is about class
hierarchies. Each class is represented as a box, shaped with three metrics: number of variables,
number of methods and number of lines of code.

The hierarchy represented here is PLAF, the pluggable look and feel of Java. You can notice the
irregularity of the hierarchies, which probably hide some missing functionalities.
javax.swing.plaf.basic.BasicTreeUI
1636 lines of code
49 variables
131 methods

System complexity [Lanza 2003]


JComponent
1888 LOC
169 methods
73 attributes

JTable
2691 LOC
185 methods
44 attributes

We can merely observe the two biggest classes of Swing: JComponent and JTable.
However, we should not blame their developers. The root of a graphical user interface framework
is inherently complex and difficult to implement. To convince yourself, have a look at the root
class of any serious GUI framework.
A class should capture one and only one key abstraction
Example in ArgoUML

We can observe a class which has 2 public methods and many private methods. This class is quite
particular in the sense that its private methods are divided into two distinct groups. Each group of
private method is used by one public method.

This is an example of a class that offers two distinct functionalities.


Object
Action-Oriented vs Object-Oriented
The god class problem

A “god” class performs most of the work, leaving


minor details to a collection of trivial classes
Do not create god classes/objects in your system.
Be very suspicious of a class whose name contains
Driver, Manager, System, Subsystem, Utility
* @version 1.158, 03/13/06
* @since JDK1.0
*/
public final class System {

/* First thing---register the natives */


private static native void registerNatives();
static {
registerNatives();
}

/** Don't let anyone instantiate this class */


private System() {
}

/**
* The "standard" input stream. This stream is already
* open and ready to supply input data. Typically this stream
* corresponds to keyboard input or another input source specified by

java.lang.System is the perfect example. It offers methods ranging from writing on the standard
streams to copying arrays and managing security.
Note that the heuristic given before is also valid for packages. Consider the package java.util.
This package contains 229 classes, most of them are collections. But it also contains the classes
Data, JapaneseImperialCalendar, Locale, Random, XMLUtils and many more unrelated classes.
In the Pharo and Squeak Smalltalk languages, the class SystemDictionary is another example of a
god class.
SystemDictionary enables one to control the garbage collectors, streaming objects, accessing
classes, querying the systems. It has little to do with the notion of dictionary!
In application that consist of an object-oriented model interaction
with a user interface, the model should never be dependent on the
interface.

The interface should be dependent on the model


In Mozilla:
dom/base/nsDOMWindowUtils.cpp

/* -*- Mode: C++; tab-width: 2; indent-


tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
...
#include "nsIDOMHTMLCanvasElement.h"
#include "nsICanvasElement.h"
#include "gfxContext.h"
#include "gfxImageSurface.h"
...

Have a look at the definition of the class nsDOMWindowUtils, which is central to the DOM
component of Mozilla.
This class has references to some graphical packages, which goes against the idea of having a
clean and modular DOM.
belong to
the core
In Mozilla:
dom/base/nsDOMWindowUtils.cpp

/* -*- Mode: C++; tab-width: 2; indent-


tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
...
#include "nsIDOMHTMLCanvasElement.h"
#include "nsICanvasElement.h"
#include "gfxContext.h" belong to
#include "gfxImageSurface.h" gfx package
...
Another example of the kernel of Pharo. The class Object contains a reference to the UIManager,
which belongs to the package ToolBuilder. The method #inform: is clearly wrongly packaged
Wrong dependency

View Model
Model-view-controller

Controller

View Model

Model-view-controller (MVC) is a software architecture,


considered as an architectural pattern
Model-view-controller

The MVC pattern isolates the domain logic from the


user interface
MVC permits
independent development

testing

maintenance (separation of concerns)


Model-view-controller

MVC is typically associated with frameworks


Update of the view by the model and/or controller is
commonly realized with the observer/observable
design pattern
About encapsulation

desired_temp?() Desired Temp

Heat flow actual_temp?() Actual Temp


regulator

anyone_in_room?() Occupancy

Home heating system without encapsulation

Example of poor system intelligence distribution


About encapsulation

get_actual_temp?() Room
get_desired_temp() Desired Temp

Heat flow
Actual Temp
regulator

is_occupied() Occupancy

Home heating system with encapsulation


About encapsulation

Room
do_you_need_heat?() Desired Temp

Heat flow
Actual Temp
regulator

Occupancy

Home heating system with distributed intelligence


Do not turn an operation into a class. Be suspicious of any class
whose name is a verb or is derived from a verb.
DigitCollector DialToneInitiator

call_buffer connector

Classes which should be operations


TelephoneCall

call_buffer
connector

A better design for telephone services


Relatio
The relationship between classes
and objects
Minimize the number of classes with which another class
collaborates
public class JTable extends JComponent implements TableModelListener,
Scrollable,
TableColumnModelListener, ListSelectionListener, CellEditorListener,
Accessible, RowSorterListener
{
...
/** The <code>TableModel</code> of the table. */
protected TableModel dataModel;

/** The <code>TableColumnModel</code> of the table. */


protected TableColumnModel columnModel;

/** The <code>ListSelectionModel</code> of the table, used to keep


track of row selections. */
protected ListSelectionModel selectionModel;

/** The <code>TableHeader</code> working with the table. */


protected JTableHeader tableHeader;
...
public class JTable extends JComponent implements TableModelListener,
Scrollable,
TableColumnModelListener, ListSelectionListener, CellEditorListener,
Accessible, RowSorterListener
{
...
/** The <code>TableModel</code> of the table. */
protected TableModel dataModel;

JTable depends on more


/** The <code>TableColumnModel</code> of the table. */
than 50 different classes
protected TableColumnModel columnModel;

/** The <code>ListSelectionModel</code> of the table, used to keep


track of row selections. */
protected ListSelectionModel selectionModel;

/** The <code>TableHeader</code> working with the table. */


protected JTableHeader tableHeader;
...
Inheri
The inheritance relationship
Inheritance

The Inheritance relationship is one of the most


important relationships within object-orientation
It is best used to capture the a-kind-of relationship
between classes
Component

Container Button

Window Frame

Example of the core of java.awt


JComponent
accessibleContext
listenerList JButton
...
AbstractButton
itemListener
changeEvent, ...
AbstractButton
itemListener
changeEvent JComponent
accessibleContext
... listenerList
...

JButton
...
@OOPSLA’89
“In Figure 2 an example of a class is given. Class Window is
described as a subclass of class Stream. ...”
“In Figure 2 an example of a class is given. Class Window is
described as a subclass of class Stream. ...”

Do you think a window can be considered as a stream?


Collection

... Link

LinkedList Process

Semaphore

Probably a semaphore can be seen as a collection, but is it


worth subclassing LinkedList in that case?
All abstract classes must be base classes
All abstract classes must be base classes

Since an abstract class cannot be instantiated, does it make sense


to have an abstract class leaf?
Mistaking objects for derived classes

CarManufacturer

GeneralMotors Ford Chrysler

Consider the inheritance hierarchy given on this slide. At first view the inheritance hierarchy looks
correct. GeneralMotors, Ford and Chrysler are all special types of car manufacturers. On second
thought, is GeneralMotors really a special type of car manufacturer? Or is it an example of a car
manufacturer? This is a classic error and it causes proliferation of classes.

how many GeneralMotors objects are there? Ford objects? Chrysler objects? The answer for all
three classes if one. In this case they should have been objects.

Keep in mind that not all derived classes that have only one instance in your system are
manifestations of this error, but many will be.
It should be illegal for a derived class to override a base class
method with a NOP method, that is, a method that does nothing
Dog wag_tail() {...}

DogNoWag wag_tail() { /* empty */}

What is wrong with this design?

Consider a class Dog. The behaviors that all Dogs know how to carry out is bark, chase_cats and
wag_tail. Consider that we want to have a dog that does not wag its tail, let’s say DogNoWag. This
new class is exactly like a Dog except it doesn’t know how to wag its tail. A solution could be to
have DogNoWag inherit from Dog and override the wag_tail method with an empty method (NOP).
Dog wag_tail() {...}

DogNoWag wag_tail() { /* empty */}

This design does not capture a logical relationship


It implies the following statements:
All dogs know how to wag their tails

DogNoWag is a special type of dog

DogNoWag does not know how to wag its tail

The rules of classic logic are not being obeyed


bark() {...}
AllDogs chase_cats() {...}

DogNoWag Dog wag_tail() {...}

Dogs and their tails...


Other heuristics
When building an inheritance hierarchy, try to construct reusable
frameworks rather than reusable components
Users of a class must be dependent on its public interface, but a
class should not be dependent on its users
Minimize the number of message sends between a class and its
collaborator
A class must know what it contains, but it should not know who
contains it
All base classes should be abstract classes
All base classes should be abstract classes

Not everybody will agree with this one (including me),


but this heuristic deserves some attention
What you should know!

What is the difference between encapsulation and information


hiding?

What is the difference between an object and a class

Why is it important to have hidden data?

Why visualization is useful to understand large code?

What is a god class?

What is model-view-controller?

Why a leaf class cannot be abstract?


Can you answer these questions?

Why information hiding and encapsulation favor


maintainability?
Why god classes are dangerous for an application
health?
Why MVC requires implementing the observer/
observable design pattern?
What are the criteria to assess the quality of a class
hierarchy?
License

http://creativecommons.org/licenses/by-sa/2.5

Attribution-ShareAlike 2.5
You are free:
• to copy, distribute, display, and perform the work
• to make derivative works
• to make commercial use of the work

Under the following conditions:

Attribution. You must attribute the work in the manner specified by the author or licensor.

!
Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting
work only under a license identical to this one.

• For any reuse or distribution, you must make clear to others the license terms of this work.
• Any of these conditions can be waived if you get permission from the copyright holder.

Your fair use and other rights are in no way affected by the above.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy