1. Decoupling

The purpose of the patterns in this group is to divide a software system into several parts in such a way that individual parts can be built, changed, replaced, and reused independently. The advantage of decoupling is local change, i.e., the system can be changed by modifying one or only a few parts, instead of changing everything.

In comparison to the following category on integration, the emphasis in these patterns is on how to split a system into components, not on combining them.

The patterns in this category differ greatly in their range of applicability. The patterns Module, Abstract Data Type, and Hierarchical Layers, for example, have an extremely broad applicability, whereas Iterator, Proxy, Facet, or Visitor apply in much narrower design situations.

Module

Purpose: group together components that change together, hide them behind change-insensitive interface.

Flexibility: change/replace implementation, hardware, I/O, OS, memory resources, etc. without affecting clients.

Implementation: make interface independent of likely changes (information hiding).

Note: Modules are supported by Java interfaces, Modula modules, Ada packages, or even .h,.c, and .o files in C. Normally, it is not possible to instantiate a module more than once (there is no progr. language construct for doing this). Instead, compiling and linking a module instantiates it.

Abstract Data Type (Class)

Purpose: hide data structure and access algorithms behind change-insensitive interface.

Flexibility: change/replace implementation, hardware, I/O, OS, memory resources, etc. without affecting clients.

Implementation: make interface independent of likely changes (information hiding).

Note: the intent of ADT is similar to that of module, but an ADT is typically smaller (single data type). It is also possible to create multiple instances of an ADT. For a module, there is normally only one instance and a module may combine several related ADTs.

Examples of ADTs:

Repository (Data Base)

Purpose: provide a central data structure with access interface for multiple clients.

Flexibility: clients are independent of each other; add/remove clients; change implementation of data structure.

Implementation: get/set or query/update methods; synchronization for parallel access (e.g., transaction).

See also: Blackboard

Client/Server

Purpose: distributed repository, where clients and server (=repository) run on different computers connected by some network.

Manager (Collection)

Purpose: place collection-related functions such as creation/deletion, registration, search, layout and display into a manager class, separate from the objects in the collection.

Flexibility: change/replace/reuse manager.

Implementation: use Singleton for the manager component.

Iterator (Robust Iterator)

Purpose: provide an interface for sequentially accessing components in an aggregate/container.

Flexibility: vary internal structure of aggregate/container; multiple iterators may operate simultaneously on the same object.

Implementation: separate iterator state from aggregate/container; standardized interface for iteration.

Other Examples

Many more examples for abstract data types exist (container classes, graphs, matrices, streams, threads, etc.)

Layers (Hierarchical Layers)

Purpose: a (software) layer provides a set of instructions, potentially using lower layers in the usage hierarchy.

Flexibility: extension/contraction(partial reuse)/replacement; incremental build and test.

Implementation: uses-relation among layers must be acyclic.

Examples:

Bridge

Purpose: let abstraction and implementation evolve separately.

Flexibility: abstraction and implementation evolve independently; can add new abstraction or implementation without affecting the other.

Implementation: separate layers for abstraction and implementation, fixed interface of implementation.

Facade

Purpose: provide unified, convenient interface to a set of existing interfaces, hide some components.

Flexibility: change/replace "hidden" subsystems including interface.

Implementation: facade calls hidden subsystem interfaces.

Proxy (Surrogate)

Purpose: add/withdraw unplanned functionality transparently.

Flexibility: add/withdraw functionality without affecting original object or clients, without subclassing.

Implementation: proxy has same interface as original; delegate request to original before/after adding functionality.

  • Decorator (Cascading Proxies)
  • Buffer Proxy, Cache Proxy
  • Logging Proxy, Counting Proxy
  • Firewall (Protection Proxy)
  • Synchronization Proxy
  • Remote Access Proxy

Facet (Extension Object)

Purpose: add new interfaces to existing classes without changing the classes; provide multiple views.

Flexibility: extend interface, extend functionality

Implementation: An object registers its extensions and returns them if queried.

Framework

Purpose: provide a complete or nearly complete application layer that can be extended by subclassing.

Flexibility: add new subclasses where permitted, without changing application logic in framework.

Implementation: uses subclassing, template methods, factory methods, builders, abstract factories.

Visitor

Purpose: add new operations to stable class hierarchy without changing classes.

Flexibility: a) decouple operations that exist in variants for many classes from those classes; b)extensibility: add new operations.

Implementation: common accept interface in classes; methods for all classes in visitor.

Variations:

Previous group Next group Back to the top