Midterm review CC-BY-NC

Maintainer: admin

1Class design and encapsulation

1.1Example: java.util.Date

boolean after(Date when) and boolean before(Date when) provide a total ordering of the class. long getTime() and void setTime(long time) provides conversion between Date objects and the number of milliseconds from the "epoch". In order to know the specific month/day of a Date, the GregorianCalendar class has to be used to assign descriptions to points in time. The Java library designers provide a superclass Calendar so you can implement many different types of calendars.

1.2Designing a Day Class

We want to design a class to answer these questions:

  • How many days are there between now and the end of the year?
  • What day is 100 days from now?

We can design methods like int daysFrom(Day day) and Day addDays(int n). We also observe that addition and subtraction can be applied to Days.

We also want a constructor that constructs a Day Object from a given year, month and day, and we want methods to obtain these attributes.

1.3Operator Overloading

In some languages (C++, python) you can overload the behavior of operators such as + and - for specific classes. In java, you can't, because some bitch thought it'd make the language too hard for noobs.

1.4Three Implementations of the Day Class

The first implementation stores the year, month, and day in separate variables. This is bad because it is very inefficient to do computation on the day.
The second implementation stores the day as the julian day, which is the number of days from Jan 1, 4713 BC. Computations on the day become efficient, but obtaining the month/year of the day becomes inefficient.
The third implementation combines the first two implementations, and stores both informations, and lazily converts them (only when necessary).

1.5Importance of Encapsulation

1.5.1Accessors and Mutators

Mutator method
Modifies the state of an object
Accesor method
Reads the state of an object
  • Not every field needs a getter and a setter
  • You can share references for immutable classes
  • For attributes which you don't want people to change via accessor classes, you should clone them before getting the state of it.

1.5.2Final Instance Fields

The final keyword is used to express that the variable is immutable, but it only refers to the value of the variable, not the reference of it.

1.5.3Separation of Accessors and Mutators

Accessors should not change the state of the object whenever it's called. A method that changes the object state should ideally not return anything.

Exception: The Scanner.next() method returns the next token from the input, at the same time it mutates the Scanner object so the next time you call it, a different token is returned. Why did the designers do it this way? Probably because they're bad.

Exception: The Queue.remove() method modifies the state of the queue by removing the head, but it also returns whatever is removed.

1.5.4Side Effects

Side Effect
Data modification that is observed when the method is called.

A method can modify the implicit parameter, explicit parameter, and accessible static fields.

1.5.5The Law of Demeter

A method should only use:

  • Instance fields of its class
  • Parameters
  • Objects that it constructs with new

1.6Analyzing the Quality of an Interface

1.6.1Cohesion

A class is cohesive if all of its methods are related to a single abstraction.

1.6.2Completeness

A class should support all the operations that are part of the abstraction that the class represents.

1.6.3Convenience

A class should make common tasks easy to do.

1.6.4Clarity

A class should make its methods easy to understand and intuitive to use.

1.6.5Consistency

Operations in a class should be consistent with each other with respect to names, parameters, return values, and behavior. E.g. 0-indexed counts and 1-indexed counts.

2Cloning

A cloning method is expected to fulfill these three conditions:

  • x.clone() != x
  • x.clone().equals(x)
  • x.clone.getClass() == x.getClass()

Any objects that is willing to be cloned must implement the Cloneable interface. The Cloneable interface has no method, thus it is a "tagging" interface type, it is only used in code such as:

if (x instanceof Cloneable) {}

A CloneNotSupportedException is thrown if an object cannot be cloned, it is a checked exception so any cloning operations must be caught.

Object.clone() makes a shallow copy. If the fields are references, the references aren't copied. To implement a deep or sufficiently deep copy, you must implement it yourself.

3Design by Contract

3.1Preconditions

Something that must be true before the method carries out its operations, it is specified by the @precondition tag in the javadoc.

3.2Assertions

assert statement throws an AssertionError if statement evaluates to false.

assert statement: "explanation" throws an AssertError and provides the explanation for the error thrown

3.3Exceptions in the Contract

Sometimes instead of using asserts, you throw exceptions. This, unlike assertions, cannot be turned off and incurs a small performance penalty.

3.4Postconditions

Something that a method promises to fulfill after it carried out its operation. It is specified by the @postcondition javadoc tag. If a postcondition is not fulfilled, do not throw an exception because you're the one who fucked up.

3.5Class Invariants

A logical condition that holds for all objects of the class that is not undergoing mutation - conditions that must be true before and after every method call, but it can be violated inside the method call.

To prove a class invariant, you must check

  • It is true after every constructor finished execution
  • Every mutator preserves it

Interface invariants are conditions that involve only the public interface of a class. Implementation invariants involve the details of a particular implementation.

4Unit Testing

Do it

5Interface Types and polymorphism

If a method has an interface as a parameter, you can supply an object of any class that implements it.
An interface type has no implementation, it merely specifies a set of methods. All methods are automatically public. An interface type cannot specify instance variables.
Any variable which is specified in the interface are automatically declared as public static final.
Interfaces can extend other interfaces.

5.1Polymorphism

Type of an object is never an interface type, but the type of a variable can be an interface type. This variable contains reference to an object whose class implements that interface.

Polymorphism refers to the ability to run different code according to the actual type of an object. If a call is made to one of an interface type variable's methods, different code will be ran depending on the implementing class of that interface variable.

5.2The Comparable Interface Type

The call object1.compareTo(object2) have three possible return values.

  • negative value, if object1 comes before object2
  • zero, if the objects are equal
  • positive value, otherwise.

Collections.sort() requires the object to be sorted to implement Comparable in order to have a natural ordering.

5.3The Comparator Interface Type

Sometimes you want to sort a collection by different ways. For example, you want to sort students in lexical order of their family name and also of their given name. It is impractical to rewrite the compareTo() method every time, thus you can supply an object which implements the Comparator<T> interface type, which specifies how two objects of type T is compared.

Example

public class StudentGivenNameComparator implements Comparator<Student> {
    public int compare(Student student1, Student student2){
        //implement it
    }
}
public class StudentFamilyNameComparator implements Comparator<Student> {
    public int compare(Student student1, Student student2){
        //implement it
    }
}

5.4Anonymous Classes

They are classes that are not explicitly named and declared. It is declared if you only need the object once. The syntax to do so is:

    MyClass foo = new MyInterface(){
        // implementation of anonymous class
    };

6Object-oriented design with UML

6.1UML Class Diagrams

The UML format is attributeName : Type. For methods, it is methodName() : returnType

For the 'has' relationship, multiplicity is written on the end points of the connection, the common choices are:

  • Any number: *
  • One or more: 1..*
  • Zero or one: 0..1
  • Exactly one: 1
Dependency
A class depends on another class if it uses objects of the other class
Aggregation
A class aggregates another if its objects contain objects of the other class
Inheritance
If you don't know this, consider dropping this course
Composition
Stronger form of aggregation where contained objects do not have an existence outside of their container
Association
Very general relationship between two classes, you can write roles at the end of lines
Directed association
One way association, e.g. A message queue needs to know about the message it contains, but the message doesn't need to know anything about its message queue.
Interface Type Implementation
Implements the interface

6.2Sequence Diagrams

A sequence diagram shows the time ordering of a sequence of method calls. Sequence diagrams describe interactions between objects. Underline is used to distinguish object rectangles from class rectangles. The vertical line that emanates from the object is called the lifeline. In some object-oriented programming languages, objects can be explicitly destroyed. The rectangles along the lifelines are called activation bars, they show when the scope is inside the object. Activation bars start at the end of the call arrow, and ends when the method returns.
If a method constructs a new object, you draw a line with <<create>> written on top of it to indicate the timing of the creation.

6.3State Diagrams

A state diagram shows the states of an object and the transitions between states. They are just boxes with states written inside it, and labelled directed edges that indicate transition. If you have taken COMP 330 and did finite state automata, they are very similar.

7Design Patterns: Observer and Strategy

7.1The Iterator as a Pattern

Iterators do not expose the internal structure of a collection class. Iterators are superior to cursors as you can attach more than one iterator to a collection.

7.2The Pattern Concept

Every pattern has:

  • A short name
  • A brief description of the context
  • A lengthy description of the problem
  • A prescription for a solution

A design pattern gives advice about a problem in software design. The Iterator pattern teaches how to access the elements of an aggregate object.

Example:

Iterator pattern:

Context

  1. An object (aggregate) contains other objects (elements)
  2. Clients (methods that use the aggregate) need access to the elements
  3. The aggregate should not expose its internal structure
  4. There may be multiple clients that need simultaneous access

Solution

  1. Define an interator class that fetches one element at a time
  2. Each iterator object needs to keep track of the position of the next element to fetch
  3. If there are several variations of the aggregate and iterator classes, it is best if they implement common interface types.

7.3The Observer Pattern

The key to implementing this behavior is the *model/view/controller architecuture". The model holds the information in some data structures, the view draws the visible parts of the data that is displayed, and each view has a controller, which is an object that processes user interaction.

Context

  1. An object (subject) is the source of events
  2. One or more objects (observers) wants to know when an event occurs

Solution

  1. Define an observer interface type
  2. Subject maintains a collection of observer objects
  3. Subject class supplies methods for attaching observers
  4. Whenever an event occurs, the subject notifies all observers

7.4Layout Managers and the Strategy Pattern

You add user interface components to a container (buttons, textfields). A layout manager arranges the components in a container.

The strategy pattern teaches how to supply variants of an algorithm. A layout manager tells a container how to arrange its components. The pattern tells us to put the algorithm in a strategy interface type, by supplying objects of different classes that implement the strategy interface type, the algorithm can be varied.

Context

  1. A class (context) can benefit from variants of an algorithm
  2. Clients of the context class sometimes want to supply custom versions of the algorithm

Solution

  1. Define an interface type that is an abstraction for the algorithm (strategy)
  2. Concrete strategy classes implement this interface
  3. Client supplies a concrete strategy object to the context class
  4. Whenever the algorithm is executed, the context class calls the appropriate methods of the strategy object

8Design Patterns: Composite and Decorator

8.1Components, Containers, and the Composite Pattern

The composite pattern teaches how to combine several objects into an object that has the same behavior as its parts.

Context

  1. Primitive objects that can be combined into composite objects.
  2. Clients treat a composite object as a primitive object.

Solution

  1. Define an interface that is an abstraction for the primitive object
  2. A composite object contains a collection of primitive objects
  3. Both primitive classes and composite classes implement that interface type
  4. When implementing a method from the interface type, the composite class applies the method to its primitive objects and combines the results.

8.2Scroll Bars and the Decorator Pattern

The Decorator pattern teaches how to form a class that adds functionality to another class while keeping its interface.

Context

  1. You want to enhance the behavior of a class (component class)
  2. Decorated component can be used in the same way as a plain component
  3. Component class does not take on the responsibility of the decoration
  4. Open ended set of possible decorations

Solution

  1. Define an interface type that is an abstraction for the component
  2. Concrete component classes implement this interface type
  3. Decorator classes also implement this interface type
  4. Decorator object manages the component object it decorates

8.3How to Recognize Patterns

Just memorize them

8.4Putting Patterns to Work

Memorize them harder

9Inheritance-based reuse

9.1The Concept of Inheritance

9.1.1Using Inheritance for Modeling Specialization

Specialized subclasses inherit from superclasses that represent more general concepts. A subclass adds more methods and fields, and it extends the capabilities of the superclass. Subclasses can override methods and giving new behavior to a method taht exists in the superclass. Subclass automatically inherits the methods in the superclass.
A final method cannot be overridden. A final class cannot be extended.

9.1.2The Super/Sub Terminology

Superclass = general, subclass = specific

9.1.3Inheritance Hierarchies

Sets of classes can form inheritance hierarchies

9.1.4The Substitution Principle

Liskov Substitution Principle
You can substitute a subclass object whenever a superclass object is expected, since a subclass inherits the behavior of its superclass.

9.1.5Invoking Superclass Methods

You can't access features that are labeled private in the superclass, you can however do so, if the features are labelled as protected in the super class.

9.1.6Invoking Superclass Constructors

Use super() to invoke the superclass constructor. If the subclass does not call a superclass constructor, the superclass constructor with no parameters is called automatically.

9.1.7Preconditions and Postconditions of Inherited Methods

A subclass method can only require a precondition that is at most as strong as the precondition of the method that it overrides. A subclass method must ensure a postcondition that is at least as strong as the postcondition of the method that it overrides.

In general, when you override a method, you cannot make it less accessible, or throw more checked exceptions than are already declared in the superclass method.

9.2Graphics Programming with Inheritance

9.2.1Designing Subclasses of the JComponent Class

Drawing shapes, subclass the JComponent class and override the paintComponent() method.

9.2.2Listener Interface Types and Adapter Classes

Listener interfaces have empty methods for all the behaviors, Adapter classes all implement the Listener interfaces, but provide an empty method body for each method. To define a new listener, just extend an adapter class and only overrried the behaviors required.

10Abstract Classes and the Template Method design pattern

10.1Abtract Classes

Abstract methods are undefined and must be defined in a subclass. A class with one or more abstract methods must be declared as abstract.
Objects of an abstract class cannot be constructed. Abstract classes can have instance fields and methods.

10.2The Template Method Pattern

The Template Method pattern teaches how to supply an algorithm for multiple types, provided that the sequence of steps does not depend on the type.

Context

  1. An algorithm is applicable for multiple types
  2. The algorithm can be broken down into primitive operations. The primitive operations can be abstract
  3. Order of the primitive ops doesn't depend on the type

Solution

  1. Define an abstract superclass that has a method for the algorithm and abstract methods for the primitive operations
  2. Implement the algorithm to call the primitive operations in the appropriate order
  3. Do not define the primitive operations, or define them to have appropriate default behavior
  4. Each subclass defines the primitive operations but not the algorithm

10.3Protected Interfaces

A protected feature can be accessed by methods of all the subclasses. Protected fields should be avoided because they have the same disadvantages as public fields. Classes in the same package also has access to protected features, even if they don't belong in subclasses.

10.4The Hierarchy of Swing Components

10.5The Hierarchy of Standard Geometric Shapes

10.6When Not to Use Inheritance

10.6.1Points and Circles

Inheritance is used for is-a relationships, and aggregation is used for has-a relationships. A circle is not a subclass of a point.

10.6.2Vectors and Stacks

A stack is not a subclass of a vector because not all methods for a vector makes sense for a stack. A stack inherits all methods of the vector class. Don't use inheritance if it violates the Liskov substitution principle.

11Error Handing

11.1The Hierarchy of Exception Classes

Subclasses of Error describe fatal errors, such as memory exhaustion or assertion failure. RuntimeException are unchecked exceptions.
A catch clause catches exceptions of a given class or any of its subclasses.

12Facade, Singleton, Command, Prototype Patterns

12.1The Facade Pattern

Context

  1. A subsystem consists of multiple classes, making it complicated for clients to use
  2. The implementation of the subsystem is subject to change, but the functionality that it provides is stable
  3. In order to provide the reuse of components, you want to give a coherent entry point to the capabilities of the subsystem

Solution

  1. Define a facade class that exposes all capabilities of the subsystem as methods
  2. The facade methods delegate requests to the subsystem classes
  3. The subsystem classes do not know about the facade class

12.2The Singleton Pattern

A singleton class has exactly one instance. The singleton pattern teaches how to implement a class that has exactly one instance

Context

  1. All clients need to access a single shared instance of a class
  2. You want to ensure that no additional instances can be created accidentally

Solution

  1. Define a class with a private constructor
  2. The class constructs a single instance of itself
  3. Supply a static method that returns a reference to the single instance

12.3The Command Pattern

Context

  1. You want to implement commands that behave like objects, either because commands store information, or they're to be collected

Solution

  1. Define a command interface type with a method to execute the command
  2. Supply methods in the command interface to manipulate the state of command object
  3. Each concrete command class implements the command interface type
  4. To invoke the command, call the execute method

12.4The Prototype Pattern

Context

  1. A system needs to create several kinds of objects whose classes are not known when the system is built
  2. You do not want to require a separate class for each kind of object
  3. You want to avoid a separate hiearchy of classes whose responsibility it is to create the objects

Solution

  1. Define a prototype interface that is common to all created objects
  2. Supply a prototype object for each kind of object that the system creates
  3. Clone the prototype object whenever a new object of the given kind is required