Updated on 24 Jun, 202622 mins read 15 views

In the previous chapter, we learned how to discover objects from requirements.

Suppose we analyzed an e-commerce system and identitifed:

Customer
Order
Product
Cart
Payment

Now a new question appears:

Who calculates the order total?
Who validates payment?
Who updates inventory?
Who creates orderes?
Who sends notifications?

Finding objects is only half the problem.

The harder problem is: Assigning Responsibilities Correctly

This is where most poor designs are born.

The Fundamental Problem

Imagine we are designing an ATM.

Requirement:

Customer withdraws money.

Who should perform the withdrawal?

Possible answers:

Customer
ATM
BankAccount
Database
Transaction

A beginner often chooses randomly.

An architect does not.

There must be a systematic way to decide.

Responsibilities Assignment was created to solve exactly this problem.

What Is a Responsibility?

A responsibility is:

Something an object knows or something an object does.

Every responsibility falls into one of two categories.

Type 1 – Knowing Responsibilities

Information an object owns.

Example:

class Customer
{
private:
    string name;
    string email;
};

Customer knows:

Name
Email
Address
Phone Number

These are knowing responsibilities.

Type 2 – Doing Responsibilities

Actions an object performs.

Example:

class Customer
{
public:
    void placeOrder();
};

Customer performs:

Place Order
Update Profile
Cancel Subscription

These are doing responsibilities.

Simple Mental Model

Every object should answer:

What do I know?
What do I do?

Nothing more.

Nothing less.

Why Responsibility Assignment Matters

Consider the design.

class Customer
{
public:

    void placeOrder();

    void calculateTax();

    void processPayment();

    void updateInventory();

    void generateInvoice();

    void sendEmail();

    void scheduleDelivery();
};

Question:

Is Customer really responsibel for all of this?

Obviously not.

This is the beginning of a: God Object

What Is a God Object?

A God Object is an object that knows too much and does too much.

Example:

class SystemManager
{
public:

    void loginUser();
    void processOrder();
    void printInvoice();
    void updateStock();
    void sendEmails();
    void generateReports();
    void handlePayments();
};

Everything goes into one class.

Symptoms:

Huge class
Thousands of lines
Many dependencies
Difficult testing
Frequent bugs

God Objects are among the most common design failures.

Responsibility Assignment Goal

The goal is:

High Cohesion
Low Coupling

We studied these concepts earlier. Now we apply them.

Example: Order Total Calculation

Requirement:

Calculate order total.

Possible candidates:

Customer
Order
Product
PaymentService

Question:

Who should calculate the total?

Let's analyze.

Customer

Knows:

Profile
Address
Orders

Not ideal.

Product

Knows:

Price
Inventory

Only individual product information.

PaymentService

Responsible for payments.

Not totals.

Order

Knows:

Items
Quantities
Prices

Perfect.

Therefore:

class Order
{
public:
    double calculateTotal();
};

Responsibility assigned correctly.

Responsibility Should Follow Information

One of the most important design principle:

Behavior should live near the information it uses.

Bad design:

class Customer
{
public:

    double calculateOrderTotal(Order& order);
};

Customer does not own order data.

Better Design:

class Order
{
public:

    double calculateTotal();
};

Order owns the information.

Order knows the behavior.

Example: Library System

Requirement:

Determine whether a book can be borrowed.

Possible objects:

Book
Member
Library
Loan

Question:

Who should decide availability?

Book knows:

Available Copies
Current Status

Therefore:

class Book
{
public:

    bool isAvailable();
};

Book has the required information.

Book gets the responsibility.

Information Expert Principle

This idea is so important that later GRASP formalizes it.

The rule:

Give responsibility to the object that has the information required to fulfill it.

Example:

Requirement:

Calculate Shopping Cart Total

Who has:

Products
Prices
Quantities

Answer:

Cart

Therefore:

cart.calculateTotal();

Cohesion and Responsibility

High cohesion means:

Related responsibilities stay together.

Example:

class Order
{
public:

    addItem();

    removeItem();

    calculateTotal();

    markPaid();
};

All responsibilities relate to order.

High cohesion.

Bad Example:

class Order
{
public:

    calculateTotal();

    sendEmail();

    generateReport();

    resizeImage();

    uploadVideo();
};

Low cohesion.

Responsibilities unrelated.

Responsibility Assignment Example

Food Delivery System

Objects:

Customer
Restaurant
Order
DeliveryPartner
Payment

Requirement:

Track Order Status

Possible owners:

Customer
Restaurant
Order

Who owns status?

Order

Therefore:

class Order
{
public:

    void updateStatus();

    OrderStatus getStatus();
};

Requirement:

Prepare Food

Who owns preparation?

Restaurant

Therefore:

class Restaurant
{
public:
	void prepareOrder();
};

Requirement:

Deliver Food

Owner:

DeliveryPartner

Correct responsibility assignment.

The Danger of Anemic Models

A very common beginner design:

class Customer
{
public:
    string name;
};

class Order
{
public:
    double total;
};

class Product
{
public:
    double price;
};

No behavior.

Only data.

Then:

class OrderService
{
public:

    void calculateTotal();

    void validateOrder();

    void processOrder();
};

All behavior moved elsewhere.

This creates: Anemic Domain Models

Why Anemic Models Are Bad

Problems:

Objects become data containers.

Business rules become scattered.

Low cohesion.

Hard maintenance.

Weak encapsulation.

Objects should contain meaningful behavior.

Rich Domain Models

Better:

class Order
{
public:

    void addItem();

    void removeItem();

    double calculateTotal();

    void markPaid();
};

Behavior stays with data.

This creates stronger models.

Responsibility Assignment Workflow

Professional designers often follow this sequence.

Step 1: Read Requirement

Customer places order.

Step 2: Identify involved objects

Customer
Order

Step 3: Identify required behavior

Place Order

Step 4: Ask:

Who has the information?

Who owns the process?

Who naturally fits the responsibility?

Step 5: Assign responsibility

Example:

customer.placeOrder();

or:

order.create();

depending on domain analysis.

Buy Me A Coffee

Leave a comment

Your email address will not be published. Required fields are marked *