liveBook · Manning

Don't repeat yourself principle

As explained in Object-Oriented Software Design in C++

The Don't Repeat Yourself Principle states that every piece of knowledge or behavior should have a single authoritative representation in a system.

The Don't Repeat Yourself Principle says that each piece of knowledge or behavior should have one authoritative representation. Repeated code enlarges a program, makes maintenance harder, and creates change leaks: one copy may be missed or changed differently from the others. section 2.3.3 section 2.4

Use duplication as a design warning, then refactor toward shared behavior:

  • Spot similar operations that multiply as requirements grow, such as overloaded add() and find() functions for each book kind. section 2.3.3
  • Extract the repeated behavior into one cohesive function or class instead of maintaining parallel copies. section 2.3.3
  • Check whether the refactoring also removes unnecessary subclasses, runtime type checks, and type conversions. section 2.3.4
  • Keep the authoritative representation where changes naturally belong; the final design changes Attributes without modifying Book or Catalogue. section 2.3.4

Refactoring a book catalogue

A subclass-based catalogue defines separate Fiction and Cookbook classes, overloaded add() and find() functions, and dynamic_cast calls to identify matching types and attributes. Adding how-to books repeats the same structure again. A DRY redesign stores attributes as key–value pairs in one Attributes class, then gives Catalogue one add() function and one find() function. Searches can match only the supplied attributes, so a query for REGION: China returns Chinese cookbooks without requiring a cookbook-specific search function. section 2.3.3 section 2.3.4

Listing 2.28 (Program 2.4 Books-4): Catalogue.cpp
#include "Book.h"
#include "Catalogue.h"

void Catalogue::add(Attributes * const attrs)                     #1
{
    booklist.push_back(new Book(attrs));
}

vector<Book *>Catalogue::find(const Attributes& target_attrs)     #2
    const
{
    vector<Book *> matches;
    for (Book *book : booklist)
    {
        Attributes *book_attributes = book->get_attributes();
        if (book_attributes->is_match(target_attrs))
        {
            matches.push_back(book);
        }
    }

    return matches;
}
#1 Only one add() member function
#2 Only one find() member function

Inspect the unified Catalogue implementation: one add() function constructs Book objects, and one find() function delegates matching to Attributes. section 2.3.4

How Object-Oriented Software Design in C++ covers it

How deep it goes
Explains maintenance risks and demonstrates refactoring from duplicated subclasses to shared key–value behavior.
Examples
Uses fiction, cookbook, and how-to books; overloaded Catalogue operations; dynamic_cast; and key–value searches.
What it assumes
Assumes familiarity with classes, subclasses, overloaded functions, and runtime type checks while illustrating their replacement.
What you can do after
Apply it by consolidating repeated operations into shared functions or cohesive classes and localizing future changes.
How it connects
Connects duplication with encapsulation, subclasses, runtime type checking, and the Open-Closed Principle.

Also explained in

Compare how 10 books explain don't repeat yourself principle →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Object-Oriented Software Design in C++. The section links point to the parts of the book it draws on.