liveBook · Manning

Abstraction

As explained in Unit Testing Principles, Practices, and Patterns

An abstraction is a representation that captures common behavior across multiple implementations while hiding implementation-specific details.

An abstraction captures behavior shared by multiple implementations while hiding implementation-specific details. Genuine abstractions are discovered after variation exists, not invented speculatively. section 8.4

Use abstraction to clarify real variation and improve testability:

  • Require at least two implementations before treating an interface as a genuine abstraction; a single-implementation interface does not create loose coupling by itself. section 8.4
  • Avoid speculative abstractions for future functionality; apply YAGNI and implement new behavior when the actual need appears. section 8.4
  • Extract complex private logic into a separate class when public behavior cannot test it adequately, rather than exposing the private method. section 11.1 section 11.8

Extracting pricing logic

When Order.GenerateDescription relies on a complex private GetPrice method, extract that logic into PriceCalculator.Calculate(customer, products). The pricing rules become independently testable without making implementation details public. section 11.1

Listing 11.2. Extracting the complex private method
public class Order
{
    private Customer _customer;
    private List<Product> _products;

    public string GenerateDescription()
    {
        var calc = new PriceCalculator();

        return $"Customer name: {_customer.Name}, " +
            $"total number of products: {_products.Count}, " +
            $"total price: {calc.Calculate(_customer, _products)}";
    }
}

public class PriceCalculator
{
    public decimal Calculate(Customer customer, List<Product> products)
    {
        decimal basePrice = /* Calculate based on products */;
        decimal discounts = /* Calculate based on customer */;
        decimal taxes = /* Calculate based on products */;
        return basePrice - discounts + taxes;
    }
}

Inspect the refactoring from a complex private method to a separate PriceCalculator abstraction. section 11.1

How Unit Testing Principles, Practices, and Patterns covers it

How deep it goes
Distinguishes genuine from speculative abstractions and demonstrates extraction, but stops short of formal abstraction theory.
Examples
Uses single-implementation interfaces and extracts Order.GetPrice into PriceCalculator.
What it assumes
Assumes familiarity with interfaces, public APIs, private methods, and unit testing while teaching when to extract a missing abstraction.
What you can do after
Apply abstraction by recognizing real variation, avoiding speculative interfaces, and extracting complex logic into independently testable classes.
How it connects
Connects interfaces, loose coupling, YAGNI, observable behavior, unit testing, and the Single Responsibility principle.

Also explained in

Compare how 15 books explain abstraction →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Unit Testing Principles, Practices, and Patterns. The section links point to the parts of the book it draws on.