openskills.info

Design Patterns

itSoftware engineering

Design Patterns

Design patterns give names to recurring software design problems and proven ways to organize a solution. A pattern is not a library or a code template. You adapt its roles and relationships to your context.

That distinction matters. An algorithm tells you which steps to execute. A design pattern describes how responsibilities can collaborate. Two implementations of the same pattern may look different while preserving the same intent.

Why patterns exist

Software changes. New output formats appear. External systems expose incompatible interfaces. Business rules gain variants. A design that binds every decision into one class makes each change spread.

A pattern identifies a recurring pressure and a structure that can contain it. The shared name also gives your team a compact design vocabulary. Saying “Strategy” can focus a discussion on interchangeable behavior. It does not remove the need to explain the actual business rule.

The classic catalog by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides presents 23 object-oriented patterns. The catalog groups them by intent:

  • Creational patterns vary how objects are created.
  • Structural patterns compose classes and objects into larger structures.
  • Behavioral patterns distribute algorithms and responsibilities among objects.

These categories are a map, not a selection procedure. Start with the problem and the likely direction of change. Choose a pattern only when its consequences fit both.

A pattern has more than a shape

A useful pattern description includes its intent, the problem context, participating roles, collaborations, and consequences. The consequences are where judgment begins. A pattern can make one kind of change easier while adding indirection, more types, or lifecycle rules.

Use this reading sequence:

  1. State the force that makes the current design difficult.
  2. Read the pattern's intent and applicability.
  3. Map each participant to a real responsibility in your system.
  4. Compare the benefits and costs with a direct solution.
  5. Test the smallest useful implementation.

Do not begin with “Where can I use Factory?” Begin with “Object creation now depends on a choice that changes independently.”

Five patterns that build the map

Strategy: vary an algorithm

Strategy places interchangeable behavior behind a common contract. A context delegates work to the selected strategy. Use it when one task has several policies, such as pricing or routing, and callers should not contain a growing conditional.

The trade-off is added structure. If the behavior has one stable implementation, a separate strategy hierarchy can obscure a straightforward function.

Observer: distribute notifications

Observer lets subscribers register with a provider and receive notifications when state or events change. It separates the provider from concrete subscribers. Microsoft’s .NET implementation uses observable and observer interfaces for push-based notification.

The separation creates a delivery contract you must define. Subscription lifetime, notification order, failure handling, and reentrancy do not disappear because the objects are loosely coupled.

Adapter: reconcile interfaces

Adapter converts the interface of an existing component into one a client expects. It is useful at a boundary you cannot or should not rewrite. The adapter contains translation so the client and adaptee remain focused on their own contracts.

An adapter should translate interfaces, not hide an incoherent domain model. Extensive translation may reveal that the boundary needs a clearer contract.

Decorator: add responsibilities by wrapping

Decorator gives a wrapper the same interface as the wrapped component. Wrappers can add behavior before or after delegation. This supports combinations such as buffering, compression, metrics, or authorization without creating a subclass for every combination.

Order can affect behavior. A chain of wrappers can also make runtime structure harder to inspect. Keep each decorator narrow and make composition visible.

Factory Method: defer a creation choice

Factory Method defines a creation operation while allowing a subtype or implementation point to choose the concrete product. It separates use from a creation decision that varies.

Do not treat every constructor call as a problem. Direct construction is clearer when the concrete type is stable and its creation is uncomplicated.

Patterns at different scales

The GoF catalog focuses on object-oriented class and object design. Other catalogs address different scales. Microsoft’s cloud catalog covers distributed-system concerns such as retries, circuit breakers, messaging, and data consistency. A familiar name does not guarantee identical participants or guarantees across scales.

Frameworks may also embody patterns. Dependency injection in .NET removes hard-coded dependency creation and supplies registered services through a provider. The pattern shapes the framework, while the framework supplies concrete lifecycle and resolution rules.

When patterns help

Patterns help when you can name a recurring problem, identify the changing responsibility, and explain the consequence you accept. They are especially useful during design review because they expose boundaries and trade-offs.

Patterns do not certify quality. A named pattern can still be misapplied. Warning signs include abstractions with one unlikely implementation, factories that only call one constructor, and observers with an undefined delivery contract.

Prefer the smallest design that handles the change you can justify. Refactor toward a pattern when pressure becomes visible. Remove a pattern when its promised variation no longer exists.

A practical decision loop

When you face a design problem, use this loop:

  1. Describe the behavior that must remain stable.
  2. Identify what varies and who owns that variation.
  3. Sketch a direct solution.
  4. Compare one relevant pattern by intent and consequences.
  5. Implement a small path and test it.
  6. Revisit the design after real changes arrive.

The goal is not to memorize 23 diagrams. You want to recognize design pressure, discuss it precisely, and choose an appropriate boundary.