Skip to content
academia.sh

Course Intermediate

Design Patterns

By the end of this course

Start course

01

Creational Patterns

Separating the knowledge of how an object gets built from the code that uses it: defining the pattern concept with its problem–solution–consequences triad, abstracting creation with the factory method and the abstract factory, sequencing a multi-parameter setup step by step, creating by copying, critiquing the singleton object in terms of global state, and moving the creation responsibility outside with dependency injection.

  1. 01 Pattern Concept Defining a pattern as the triad of problem, solution, and consequences: applying a registry solution already familiar from two separate lessons to carrier selection in the shipping library, measuring the two versions that produce the same output by file count, import edge count, the number of spots where a type name appears, and the longest import path, and counting the gain and the cost separately.
  2. 02 Factory Method and Abstract Factory Pulling object creation into a method and a family producer: the factory method, where the subtype decides which tariff to build; the abstract factory, which produces the matching triad of tariff, route, and label together; counting the wrong combinations silently accepted at the call site in the matching version; and comparing the file count edited when a new carrier family is added.
  3. 03 Builder Building a multi-field object step by step: comparing an eight-positional-parameter call against a builder made of named steps under the same mutation set, counting how many swapped arguments and missing fields each design silently accepts, the drop in the highest parameter count passed, and the pattern's cost in lines.
  4. 04 Prototype Creating an object by copying an existing one instead of constructing it: comparing a version that hand-writes derived tariffs' fields against one that clones a prototype, measuring the missing-field count when a field is added to the prototype, counting the child objects a shallow copy shares, and the cost of the derivation chain returning as a silent change.
  5. 05 Singleton Measuring, in terms of testability, holding a single instance as global state: applying the same four tests to a module-level single-instance registry and an instance-producing registry, counting the failed test count, whether the result changes when the test order changes, and the number of names the reset mechanism adds to the exposed surface.
  6. 06 Dependency Injection Moving the creation responsibility from the using code to the composition root: comparing a fee module that builds its own dependencies against a version that takes them at call time by direct dependency count and import closure size, counting the file edited when the discount policy changes, and showing that the closure does not disappear but moves.

02

Structural Patterns

Organizing objects and interfaces through composition: bridging incompatible interfaces with the adapter, the separate evolution of abstraction and implementation with the bridge pattern, handling tree structures uniformly with the composite, layering behavior with the decorator, simplifying a complex subsystem with the facade, saving memory through sharing, and controlling access through the proxy.

  1. 01 Adapter Bridging incompatible interfaces: counting the files that touch two external carrier providers' dictionaries in the arrangement where translation spreads to the client and in the arrangement behind an adapter, comparing the edited files and added lines when a third provider is added, and deriving the pattern's cost in files, lines, and indirection.
  2. 02 Bridge Separate evolution of abstraction and implementation: comparing the arrangement where the report-type and output-format axes are multiplied through inheritance against the arrangement split into two hierarchies, by type, line, and output-body count; measuring the added type and lines when a third format is added; the cost of a product collapsing to a sum.
  3. 03 Composite Handling tree structures uniformly: comparing, in a consolidated shipment tree, the arrangement where four calculations each repeat the type check in their own body against the arrangement putting the leaf and the node behind the same interface, by check count; measuring the files touched when a new node type and a new operation are added; the choice between transparency and safety.
  4. 04 Decorator Adding behavior in layers: comparing, by type and line count, the arrangement that produces a subclass for every combination of four independently toggled fee additions against a decorator chain that wraps while preserving the same interface; measuring the growth when a fifth addition arrives; the cost in chain depth and order sensitivity.
  5. 05 Facade Simplifying a complex subsystem: comparing, by direct dependency count, import closure, and known-step count, the arrangement where clients sequence a six-step shipment acceptance flow themselves against the arrangement placing it behind a single entry point; measuring the difference that shows up when a step is skipped; counting the files edited when a new step is added to the flow.
  6. 06 Flyweight Saving memory through sharing: comparing, by object count and a flagged heap measurement, the arrangement where every shipment carries its own tariff copy during batch fee calculation against the arrangement gathering the unchanging tariff information into a shared object; the cost of sharing in the immutability it requires and its sharing width.
  7. 07 Proxy Controlling access by stepping in: counting the calls reaching a tariff source in a no-proxy context and in a caching-proxy context, having the virtual proxy keep the source from being built until the first request, intervening at the object level with a protection proxy, and measuring the cost in a level of indirection and stale-read count.

03

Behavioral Patterns

Organizing the distribution of responsibility and communication among objects: changing an algorithm at run time, loose coupling through event notification, turning a request into an object that can be undone, separating a fixed skeleton from its changing steps, expressing a state machine through objects, passing a request between handlers, separating traversal from operation, centralizing interaction, and the cost of needless indirection with the small-language and null-object patterns.

  1. 01 Strategy Comparing a design where the fee calculation algorithm is embedded at the call site with one where the tariff is passed as a parameter: the number of algorithms that can be tried in a single run, the number of files and lines edited when a new tariff is added, the number of files added as the pattern's cost, and the candidate implementation count that must be traced from the call site.
  2. 02 Observer Comparing calling the four jobs that run on a shipment state change directly with notifying them through subscription: the number of outgoing dependencies, the size of the import closure, which layer the edited file falls in when a fifth job is added, and the pattern's cost as the static call count dropping to zero.
  3. 03 Command Comparing writing the operations on a shipment as direct calls with turning them into objects: the number of operations that can be undone, the number of audit trail entries, the number of operation bodies edited to produce the same trail in the direct version and the common coupling that results, and the pattern's cost as the file count and the call depth.
  4. 04 Template Method Comparing sequencing the fee calculation steps separately in three carrier files with moving the skeleton to a single place: the number of lines duplicated in at least two files, the amount error produced by a deviation in step order, the number of files edited when a seventh step is added, and the pattern's cost as the total line increase and the number of empty hooks.
  5. 05 State Comparing keeping the shipment life cycle in five flags and nested conditionals with turning each state into an object that knows its own transitions: the number of invalid transitions accepted across thirty state–event pairs, cyclomatic complexity, the number of representable combinations, the number of lines changed when a new state is added, and the pattern's cost as a delayed appearance of a transition-target error.
  6. 06 Chain of Responsibility Comparing sequencing discount rules in one body against passing a request along a sequence of handlers: the number of lines that change when rule order changes, how the most complex body's cyclomatic complexity and file count grow when three new rules are added, and the pattern's cost — a request that matches no rule cannot be told apart from one that does.
  7. 07 Iterator and Visitor Comparing five operations over a route tree each carrying its own traversal code against moving traversal into an iterator and type discrimination into a visitor: the number of sites carrying traversal code, the number of files edited when traversal order changes, and the number of operations that silently return the wrong result versus the number that report the error when a new node type is added.
  8. 08 Mediator and Memento Comparing four fields in an operator form that know each other directly against gathering the routing into a single object: the number of links between fields, the number of update calls, and how the link count grows with the field count; also measuring the cost of storing state by the number of internal fields accessed from outside and the number of fields the token carries.
  9. 09 Interpreter and Null Object Comparing tariff rules written as code against a small rule language interpreted from text: the number of code files and data lines edited when a new rule is added, the rule tree's node count, catching invalid text; also measuring the representation of a missing discount as a null value versus a null object by the number of null checks and the number of call sites that throw an error.
  10. 10 Pattern Misuse Comparing a version of five behavioral patterns applied with a single implementation against a version without patterns, using the same measures: the costs in file count, meaningful lines, import closure, most complex body, and call depth, against gains that stay at zero; a combined table of the break-even points measured across this topic's nine lessons.

04

Enterprise Application Patterns

Establishing the boundary between business logic and persistence with patterns: comparing transaction script and domain model as two arrangements, weighing the consequences of active record against data mapper, moving aggregate access behind a repository and managing the transaction boundary with a unit of work, preserving the same object's uniqueness, transporting data across layers, defining the application boundary with a service layer, and modeling type at runtime.

  1. 01 Transaction Script and Domain Model Two arrangements of business logic: transaction script, which runs each scenario from start to finish, against domain model, which places the rule on the object that carries the data; counting how many places the same rule is applied, testing the two arrangements for equality on the same inputs, and weighing the domain model's file, name, and indirection cost.
  2. 02 Active Record and Data Mapper Where to place the conversion between an object and its stored record: comparing active record, which places the conversion on the object, against data mapper, which hands it to a separate mapper; counting the persistence trace and import closure in the domain module; testing the two versions for round-trip equality; and adding a second storage form without touching the domain module.
  3. 03 Repository and Unit of Work The access and write boundary of an object set held together: the application layer calling mappers by hand, against the repository that grants access to the aggregate in the domain's language and the unit of work that collects the changed rows into a single point; comparing write call, write point, and find call counts across three arrangements.
  4. 04 Identity Map Representing the same identity with a single object: measuring the separate instance count produced without and with the map, the number of fields lost when two code paths change the same record, and the number of objects the map holds in memory; showing the stale read that appears once the map's lifetime is extended.
  5. 05 Data Transfer Objects and Mappers Taking cross-layer data transport up at the pattern level: counting how direct-reading clients break when the internal model's shape changes against how clients behind a mapper do not, the number of internal field names in client code, and the mapping's line cost per field.
  6. 06 Service Layer Defining the application boundary in a single place: comparing two clients that run the scenario themselves against a service layer that writes the same scenario once; counting the infrastructure name and repeated scenario step counts in the client file, and measuring the thin service by the number of methods that only forward the call.
  7. 07 Type Object and Attribute Variants Modeling the type at runtime: comparing the arrangement that writes a class for every service type against the type object that carries the type as data; counting the number of code files carrying the type name and the cost of adding a new type; runtime validation of the property bag and the cost of the write-time check it gives up.

Start typing to search.

↑↓ Esc navigate · open · close