The book "Patterns of object-oriented design"

imageHello, habrozhiteli! More than 25 years have passed since the first print run of Design Patterns. During this time, the book from the popular turned into a cult. All over the world it is recommended to read it to anyone who wants to connect life with information technology and programming. The "Russian" language used by IT people has changed, many English terms have become familiar, patterns have entered our lives.

Here is an anniversary edition with an updated translation of the book, which has become a must-read for each programmer. “Patterns of Object-Oriented Design” replaced the “Techniques of Object-Oriented Design”.

Four first-class developers - a gang of four - bring to your attention the experience of OOP in the form of twenty-three patterns. Patterns appeared because developers were looking for ways to increase the flexibility and degree of reuse of their programs. The authors not only provide principles for using design patterns, but also systematize information. You will learn about the role of patterns in the architecture of complex systems and will be able to quickly and efficiently create your own applications, taking into account all the restrictions that arise when developing large projects. All templates are taken from real systems and based on real practice. C ++ or Smalltalk code is shown for each pattern, demonstrating its capabilities.

Foreword


The book describes simple and elegant solutions to typical problems that arise in object-oriented design.

Patterns appeared because many developers were looking for ways to increase the flexibility and degree of reuse of their programs. The solutions found are embodied in a concise and easily practicable form. The Gang of Four explains each pattern with a simple example in a clear and understandable language. The use of patterns in the development of software systems allows the designer to go to a higher level of project development. Now the architect and programmer can operate with figurative names of patterns and communicate in one language.

Thus, the book solves two problems.

First, it introduces the role of patterns in creating the architecture of complex systems.

Secondly, it allows designers to easily develop their own applications using the patterns contained in the manual.

What has changed in the 2020 edition?

  • The terminology has been updated (for example, the term "refactoring" has already taken root for the "reorganization" of the code, for the share it is "sharing" instead of "separation", and for mixin it is "admixture");
  • updated style;
  • unnecessarily bulky words have been eliminated (for example, “specification” or “instantiation.” The first can be quite adequately replaced with a “definition”, the second with “creating an instance”);
  • the book is finally called “Object Oriented Design Patterns”.

PATTERN TEMPLATE METHOD (TEMPLATE METHOD)


The name and classification of the pattern The

template method is the pattern of class behavior.

Purpose The

template method defines the basis of the algorithm and allows subclasses to redefine some steps of the algorithm without changing its structure as a whole.

Motivation

Consider the application framework, which has the Application and Document classes. The Application class is responsible for opening existing documents stored in an external format (for example, in a file). An object of the Document class represents document information after reading it from a file.

Applications built on the basis of this framework can spawn subclasses of the Application and Document classes that meet specific needs.

For example, a graphical editor defines subclasses of DrawApplication and DrawDocument, and a spreadsheet defines subclasses of SpreadsheetApplication and SpreadsheetDocument.

image

The abstract class Application defines an algorithm for opening and reading a document in the OpenDocument operation:

void Application::OpenDocument (const char* name) {
      if (!CanOpenDocument(name)) {
          //   
          return;
      }

      Document* doc = DoCreateDocument();

      if (doc) {
          _docs->AddDocument(doc);
          AboutToOpenDocument(doc);
          doc->Open();
          doc->DoRead();
      }
}

The OpenDocument operation defines all the steps for opening a document. It checks whether it is possible to open the document, creates an object of the Document class, adds it to the set of documents, and reads the document from the file.

An operation of the form OpenDocument will be called a template method that describes the algorithm in the categories of abstract operations that are replaced in subclasses to obtain the desired behavior. Subclasses of the Application class verify that they can open (CanOpenDocument) and create a document (DoCreateDocument). Subclasses of the Document class read the document (DoRead). The template method also defines an operation that allows Application subclasses to get information that a document is about to be opened (AboutToOpenDocument).

Defining some steps of the algorithm using abstract operations, the template method captures their sequence, but allows them to be implemented in subclasses of the Application and Document classes.

Applicability

Basic conditions for applying the pattern template method:

  • a single use of the invariant parts of the algorithm, while the implementation of the changing behavior remains at the discretion of the subclasses;
  • the need to isolate and localize in one class the behavior common to all subclasses in order to avoid code duplication. This is a good example of the “bracketing to generalize” technique described by William Opdyke and Ralph Johnson [OJ93]. First, differences in the existing code are revealed, which are then transferred to separate operations. Ultimately, the different code fragments are replaced by the template method from which new operations are called;
  • subclass extension management. The template method can be defined so that it will trigger hooks — see the Results section — at specific points, thereby allowing expansion only at these points.

Structure

image

Participants

AbstractClass (Application) - abstract class:

  • defines abstract primitive operations that are replaced in specific subclasses to implement the steps of the algorithm;
  • implements a template method that defines the skeleton of an algorithm. The template method calls primitive operations, as well as operations defined in the AbstractClass class or in other objects;

ConcreteClass (MyApplication) - specific class:

  • implements primitive operations that perform the steps of the algorithm in a way that depends on the subclass.

The

ConcreteClass relationship assumes that the invariant steps of the algorithm will be performed in AbstractClass.

Results

Template methods are one of the fundamental techniques for reusing code. They play a particularly important role in class libraries, as they provide the ability to bring out common behavior in library classes.

Template methods lead to an inverted code structure, which is sometimes called the Hollywood principle, implying the phrase “Do not call us, we will call you” often used in this movie empire [Swe85]. In this case, this means that the parent class invokes subclass operations, and not vice versa.

Template methods call operations of the following types:

  • specific operations (either from the ConcreteClass class, or from the client classes);
  • specific operations from the AbstractClass class (that is, operations useful to all subclasses);
  • primitive operations (i.e. abstract operations);
  • factory methods (see factory method pattern (135));
  • hook operations that implement default behavior that can be extended in subclasses. Often, such a default operation does nothing.

It is important that the template operations clearly distinguish between hook operations (which can be replaced) and abstract operations (which must be replaced). To reuse an abstract class with maximum efficiency, subclass authors need to understand what operations are intended to be replaced.

A subclass can extend the behavior of an operation by replacing it and explicitly invoking the operation from the parent class:

void DerivedClass::Operation () {
      //   DerivedClass
      ParentClass::Operation();
}

Unfortunately, it is very easy to forget about the need to invoke an inherited operation. Such an operation can be transformed into a boilerplate method to give the parent control over how subclasses extend it. The idea is to invoke a hook operation from a template method in the parent class. Then subclasses will be able to redefine exactly this operation:

void ParentClass::Operation () {
      //  ParentClass
      HookOperation();
}

In the parent class ParentClass, the HookOperation operation does nothing:

void ParentClass::HookOperation () { }

Subclasses override HookOperation to extend their behavior:

void DerivedClass::HookOperation () {
   //    
}

Implementation

When implementing a pattern template method, you should pay attention to the following aspects:

  • C++. , , . , . , , . , -;
  • . , . , ;
  • naming convention. You can highlight operations that need to be replaced by adding a prefix to their names. For example, in the MacApp framework for Macintosh applications [App89], template method names begin with the Do prefix: DoCreateDocument, DoRead, and so on.

Code Example

The following C ++ example shows how a parent class can impose an invariant on its subclasses. An example is taken from the NeXT AppKit library [Add94]. Consider the View class, which supports drawing on the screen, a kind of invariant, which consists in the fact that subclasses can change the view only when it is in focus. This requires that a specific drawing context be set (for example, colors and fonts).

You can use the template Display method to set the state. The View class defines two specific operations (SetFocus and ResetFocus), which respectively set and reset the drawing context. The View hook operation of the View class does the drawing itself. Display calls SetFocus before DoDisplay to prepare the context, and ResetFocus after DoDisplay to reset it:

void View::Display () {
      SetFocus();
      DoDisplay();
      ResetFocus();
}

In order to support the invariant, View class clients always call Display, and View subclasses always replace DoDisplay.

In the View class, the DoDisplay operation does nothing:

void View::DoDisplay () { }

Subclasses override it to add their specific drawing behavior:

void MyView::DoDisplay () {
      //   
}

Known Applications

Template methods are so fundamental that they are found in almost every abstract class. Rebecca Wirfs-Brock et al. [WBWW90, WBJ90] discuss template methods in detail.

Related Patterns

Factory methods (135) are often called from boilerplate methods. In the example in the Motivation section, the OpenDocument template method called the factory DoCreateDocument method.
Strategy (362): template methods use inheritance to modify part of the algorithm. Strategies use delegation to modify the algorithm as a whole.

»More information on the book can be found on the publisher’s website
» Table of Contents
» Excerpt

For Khabrozhiteley 25% off coupon - OOP

Upon payment of the paper version of the book, an electronic book is sent by e-mail.

All Articles