Fundamentals 13 min read

Object Modeling: Comparing Object and Data Models, OOP Principles, and Composition vs Aggregation

This article explains the philosophical basis of object‑oriented thinking, distinguishes objects from things, discusses attributes and methods, compares object‑oriented and data‑model designs with Java and SQL examples, and clarifies composition and aggregation through real‑world and code illustrations.

Architect
Architect
Architect
Object Modeling: Comparing Object and Data Models, OOP Principles, and Composition vs Aggregation

Object‑oriented thinking is presented as a way to understand and abstract the world, where an object represents a thing by its attributes and behaviors.

The article defines a thing as a combination of event (事) and object (物) , and explains that an object is the abstraction of a thing’s attributes and actions.

Core OOP concepts are highlighted: an object consists of attributes and methods . When designing, one should always consider the combination of both, not just one or the other.

It then contrasts object modeling with data modeling . In a database, only the attributes (the “物体”) are persisted, leading to an incomplete representation compared with a full object model that includes behavior.

Example: a simple financial Account model.

create table account (
    id      integer,
    balance integer,
    status  integer
);

Java class generated from the table (data model):

@Getter
@Setter
public class Account {
    private int id;
    private int balance;
    private AccountStatus status;
}

Full object‑oriented interface for the same domain:

public interface Account {
    int getId();
    int getBalance();
    AccountStatus getStatus();
    void open();
    void close();
    void credit(int amount);
    void debit(int amount);
}

Implementation of the interface with business logic:

public class Account {
    private int id;
    private int balance;
    private AccountStatus status;

    public void open() { this.status = AccountStatus.OPENED; }
    public void close() { this.status = AccountStatus.CLOSED; }
    public void credit(int amount) { this.balance += amount; }
    public void debit(int amount) { this.balance -= amount; }
}

When using a data model, business logic resides in a service (transaction script) such as:

public class AccountService {
    private final AccountRepository accountRepository;
    public AccountService(AccountRepository accountRepository) { this.accountRepository = accountRepository; }
    public Account creditAccount(int accountId, int amount) {
        var account = this.accountRepository.findById(accountId)
            .orElseThrow(() -> new AccountException("The Account was not found"));
        if (AccountStatus.OPENED != account.getStatus()) {
            throw new AccountException("The Account is not open");
        }
        account.setBalance(account.getBalance() + amount);
        return this.accountRepository.save(account);
    }
}

In an object‑model approach, the service becomes an application service that merely coordinates calls:

public class AccountService {
    private final AccountRepository accountRepository;
    public AccountService(AccountRepository accountRepository) { this.accountRepository = accountRepository; }
    public Account creditAccount(int accountId, int amount) {
        var account = this.accountRepository.findById(accountId)
            .orElseThrow(() -> new AccountException("The Account was not found"));
        account.debit(amount);
        return this.accountRepository.save(account);
    }
}

The article then discusses composition vs aggregation . Composition denotes a strong whole‑part dependency (e.g., a person and their mouth), while aggregation represents a weaker, replaceable relationship (e.g., a car and its tires).

To illustrate, a digestion process is modeled with classes Mouth , Esophagus , Stomach , and Intestine inside a Person class, showing composition. The code demonstrates the flow of food through these parts.

// Mouth
public class Mouth { public Object chew(Object food) { return food; } }
// Esophagus
public class Esophagus { public Object transfer(Object paste) { return paste; } }
// Stomach
public class Stomach { public Object fill(Object paste) { return paste; } }
// Intestine
public class Intestine { public void absorb(Object chyme) { /* absorbing... */ } }
public class Person {
    private final Mouth mouth = new Mouth();
    private final Esophagus esophagus = new Esophagus();
    private final Stomach stomach = new Stomach();
    private final Intestine intestine = new Intestine();
    public void eat(Object food) {
        var paste = mouth.chew(food);
        paste = esophagus.transfer(paste);
        var chyme = stomach.fill(paste);
        intestine.absorb(chyme);
    }
}

Finally, the article mentions the open‑source e‑commerce platform Mallfoundry , built with Spring Boot and DDD principles, and provides links for further reading.

In summary, the piece advocates using an object‑model mindset rather than a data‑model mindset, demonstrates how to model domains with attributes and behavior, and clarifies the importance of composition and aggregation in robust software design.

JavaDomain-Driven DesignData ModelingObject-Oriented DesignAggregationcomposition
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.