Content

  1. Basics of UML Class in Design
    1. Class Notations
  2. Responsibility-Driven Object-Oriented Design
    1. General Principles of Design
      1. Maintainability Evaluation
      2. Traditional Properties of a Good Design
    2. Realization Examples
      1. Information Expert
      2. Creating Objects
      3. Handling System Operations
  3. SOLID: Principles of Class Design
    1. Single Responsibility Principle (SRP)
    2. Open Closed Principle (OCP)
    3. Liskov Substitution Principle (LSP)
    4. Interface Segregation Principle (ISP)
    5. Dependency Inversion Principle (DIP)

Basics of UML Class in Design

Class Notations

Description
Association Direction of navigability. An object knows the other and can access its visible attrs & opers.
Composition Strong ownership. Whole-part association. The whole part responsible for creating its parts.
Aggregation Weak ownership. Whole-part association. The part may be in >= 1 aggregate.
Interfaces A class implements/realizes an interface. Another class uses the interface.

Responsibility-Driven Object-Oriented Design

We develop a design methodically by assigning responsibilities to a class. Major goal is maintainability.

  • Responsibility of an object
    • Knowledge
    • Behavior

Responsibilities are fulfilled by implementations of operations (methods) and collaboration with other objects.

Operation Contract

Detailed post-conditions. Describes changes of states in the Domain Model. An analysis technique (contrary to design, which describes how it is carried out).

Domain Model v.s. Design Class Diagram

General Principles of Design

Maintainability Evaluation
  • Modularity: change to one component has minimal effect to others
  • Reusability: an asset can be used in other components or systems
  • Analysability: easy to find defects or cause of failure the the system fails; easy to know where to modify when we want to change or add functionalities
  • Modifiability: easy to make modifications without introducing defects
  • Testability: easy to establish test criteria and perform tests to decide whether the criteria have been met
Traditional Properties of a Good Design
  • Good abstraction and separation of concerns
    • Form modules by grouping similar concerns together and separate them from other groups
    • Each module captures single feature and exports services through a simple interface
  • Good encapsulation/information hiding
    • Export minimum amount of details through their interface
    • Clear separation between interface and implementation -> good modifiability
  • Strong cohesion within modules & methods
    • How closely the operations within a module are related to one another
    • Group strongly-related functionalities together and keep everything else out
  • No unnecessary coupling between modules
    • Reduce the number and strength of dependencies - connections to, knowledge of, or reliance on other modules
    • Defeats almost all characteristics of maintainability
  • Once and once only (no redundancy)
  • Design for testability

Realization Examples

Information Expert

Who has the necessary information for this responsibility?

  • Lowered coupling
  • Better cohesion
  • Not to be used when:
    • Compromises seek good abstraction and separation of concerns e.g. presentation should not be a concern of domain objects
Creating Objects

A class that contains or has composition relationship with, closely uses, records, has data needed to initialize that type of object should have responsibility create that object.

Doesn't increase coupling since they already have visibilities.

  • Not to be used when:
    • Compromises seek good abstraction and separation of concerns e.g. creator has to decide which type of object to create; creation process too complex
      • Separate concerns by passing an object already knowing the rules of creation or can do it behind the interface (factory)
Handling System Operations
  • Controller: receives messages from UI and coordinates the work (to delegate)
    • Façade controller or coordinator: a class representing the overall (sub)system
      • Used when there are only a small number of events
    • Use case controller or session controller: classes created to handle all events for a particular scenario
      • Maintain high cohesion by delegating tasks to other modules

SOLID: Principles of Class Design

Responsibility-driven design may still lead to rigid or classes that still need to be improved.

  • Apply when cannot summarize the responsibility of a class without using "and"
  • Over-applied if tiny classes don't abstract a complete concept or service -> not cohesive

Single Responsibility Principle (SRP)

A class should have only 1 reason to change.

  • To achieve high cohesion
  • Responsibility: a collection of functions in a class that serves one particular actor
  • e.g. shouldn't create collaborators in constructors

Open Closed Principle (OCP)

A class is open for extension but closed for modification. Key to object-oriented approach; an application of polymorphism. Implement new requirements by adding new code instead of changing them.

  • Classes should depend on abstractions rather than concrete classes
  • Not a problem in dynamic languages

Liskov Substitution Principle (LSP)

Subtypes must be substitutable for their base types.

  • Substitution property
    • If for each object o1 of type S there is an object o2 of type T s.t. for all programs P defined in terms of T, the behaviour of P is unchanged when o1 is substituted for o2, then S is a subtype of T

A client should be able to make reasonable assumptions about the behavior of a type, and to depend on these assumptions.

  • Contract
    • A set of method pre-conditions & post-conditions
  • Reasonable assumptions
    • A subtype object can weaken the pre-conditions
    • A subtype object can strengthen the post-conditions

Interface Segregation Principle (ISP)

Clients should not be forced to depend on methods that they do not use.

  • Single class plays multiple roles
    • Split the class that different clients depend on and have unnecessary methods they would call into cohesive roles, and create interface for them

Dependency Inversion Principle (DIP)

High-level modules should not depend on low-level modules - both should depend on abstractions; abstractions should not depend on details - details should depend on abstractions.

  • Encourages reusability of higher layers
  • Adapter is used when the lower-level layer is closed, or the application requires the reuse of existing services

References

results matching ""

    No results matching ""