# BoundedDomainModel vs UnboundedDomainModel in DDDplus: Core Architecture Explained

> Understand BoundedDomainModel vs UnboundedDomainModel in DDDplus core architecture. Discover how IUnboundedDomainModel defines identity and BoundedDomainModel manages scenario-specific behavior to avoid God-class anti-patterns.

- Repository: [Funky Gao/cp-ddd-framework](https://github.com/funkygao/cp-ddd-framework)
- Tags: deep-dive
- Published: 2026-03-02

---

**In DDDplus, `IUnboundedDomainModel` defines the immutable core identity of an entity ("what it is"), while `BoundedDomainModel<T>` encapsulates scenario-specific behaviors and state ("what it does"), enabling role-based modeling that eliminates God-class anti-patterns through separation of concerns.**

The `funkygao/cp-ddd-framework` implements a sophisticated domain-driven design architecture that separates core entity identity from contextual behaviors through `BoundedDomainModel` and `UnboundedDomainModel`. Understanding the fundamental differences between these two constructs is essential for implementing scenario-driven modeling and maintaining clean architecture in complex business domains.

## Core Philosophy: Identity Versus Role

The architectural split between bounded and unbounded models addresses the fundamental DDD challenge of handling entities that participate in multiple business contexts without creating monolithic classes.

In [`dddplus-spec/src/main/java/io/github/dddplus/model/IUnboundedDomainModel.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-spec/src/main/java/io/github/dddplus/model/IUnboundedDomainModel.java), the unbounded model represents the **core, immutable attributes** of an entity—the answer to "what it **is**". This interface captures natural properties that remain constant regardless of business scenario, such as a user's identity or an order's creation timestamp.

Conversely, [`dddplus-spec/src/main/java/io/github/dddplus/model/BoundedDomainModel.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-spec/src/main/java/io/github/dddplus/model/BoundedDomainModel.java) implements the **Methodful Role** pattern, representing scenario-specific views that answer "what it **does**". Each bounded model encapsulates behaviors, rules, and state relevant only within a particular bounded context, such as a user acting as a buyer in e-commerce versus a debtor in finance.

## Technical Implementation in DDDplus Source Code

The framework provides distinct base types for each modeling approach in the `dddplus-spec` module.

**Unbounded Domain Model Interface**

Defined in [`dddplus-spec/src/main/java/io/github/dddplus/model/IUnboundedDomainModel.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-spec/src/main/java/io/github/dddplus/model/IUnboundedDomainModel.java), this interface marks the core entity. It contains no business logic specific to any use case, serving instead as the stable foundation upon which bounded models are built.

**Bounded Domain Model Abstract Class**

The `BoundedDomainModel<T>` class, located in [`dddplus-spec/src/main/java/io/github/dddplus/model/BoundedDomainModel.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-spec/src/main/java/io/github/dddplus/model/BoundedDomainModel.java), requires a generic type parameter `T` extending `IUnboundedDomainModel`. It maintains a reference to the underlying unbounded model via `protected T model`, allowing bounded implementations to access core entity attributes while adding scenario-specific methods.

## Key Architectural Differences

The separation between these model types manifests across several critical dimensions:

**Purpose and Semantics**

- **Unbounded**: Captures universal identity and natural attributes shared across all scenarios.
- **Bounded**: Encapsulates role-specific behavior and mutable state for a single bounded context.

**Lifecycle and Change Frequency**

Unbounded models exhibit **high stability** and **low change frequency**, typically containing only natural keys and immutable properties. Bounded models are **mutable and evolutionary**, changing as business rules within their specific context evolve.

**Cardinality and Relationships**

A single unbounded model serves as the foundation for **multiple** bounded models. For example, a `User` entity can simultaneously support `Buyer`, `Contact`, and `Debtor` bounded models. Each bounded model holds a reference to its underlying unbounded instance via `protected T model`, establishing a clear ownership hierarchy.

**Design Intent**

This pattern prevents the **God-class anti-pattern** by ensuring orthogonal responsibilities remain separated. Rather than accumulating methods for every possible scenario into a single entity, DDDplus distributes scenario-specific logic across discrete bounded models.

## Practical Implementation Examples

### Example 1: User Entity with Multiple Bounded Roles

The following pattern demonstrates how a single unbounded entity supports multiple contextual roles:

```java
// Core entity – shared across all contexts
class User implements IUnboundedDomainModel {
    Buyer   asBuyer()   { return new Buyer(this); }
    Contact asContact() { return new Contact(this); }
    Debtor  asDebtor()  { return new Debtor(this); }
}

// Scenario 1 – e-commerce context
class Buyer extends BoundedDomainModel<User> {
    void placeOrder() { /* … */ }
}

// Scenario 2 – social context
class Contact extends BoundedDomainModel<User> {
    List<Friend> myFriends() { /* … */ }
    void makeFriend(Contact whom) { /* … */ }
}

// Scenario 3 – finance context
class Debtor extends BoundedDomainModel<User> {
    void loan(Money amount) { /* … */ }
    void repay()           { /* … */ }
}

```

The `User` class serves as the unbounded model containing core identity, while `Buyer`, `Contact`, and `Debtor` are distinct bounded models extending `BoundedDomainModel<User>`, each encapsulating scenario-specific behavior.

### Example 2: Remote Context Integration

Bounded models also handle infrastructure concerns such as remote service integration:

```java
class ShipmentOrderBag implements IUnboundedDomainModel {
    // factory to obtain a remote-aware bounded model
    ShipmentOrderBagContextRemote inContextOfRemote(ShipmentOrderGateway gateway) {
        return new ShipmentOrderBagContextRemote(this, gateway);
    }
}

// Bounded model that talks to a remote service
class ShipmentOrderBagContextRemote extends BoundedDomainModel<ShipmentOrderBag> {
    private final ShipmentOrderGateway gateway;
    
    ShipmentOrderBagContextRemote(ShipmentOrderBag model, ShipmentOrderGateway gateway) {
        super(model);
        this.gateway = gateway;
    }
    
    public ShipmentOrderBag acquireProductionLicence() {
        // remote call, business-specific logic
        return gateway.acquireLicense(this.model);
    }
}

```

Here the unbounded `ShipmentOrderBag` remains pure domain logic, while the remote-specific integration logic is isolated in `ShipmentOrderBagContextRemote`, maintaining clean architecture boundaries.

## Summary

- **UnboundedDomainModel** (`IUnboundedDomainModel`) captures the immutable core identity of an entity—what it **is**—and remains stable across all business contexts with low change frequency.
- **BoundedDomainModel** (`BoundedDomainModel<T>`) encapsulates scenario-specific behaviors and mutable state—what it **does**—preventing God-class anti-patterns through role-based modeling.
- The framework implements this pattern in `dddplus-spec/src/main/java/io/github/dddplus/model/`, where bounded models maintain a `protected T model` reference to their unbounded counterparts.
- This architectural separation enables multiple bounded contexts to evolve independently while sharing a common unbounded core, supporting both local domain logic and remote infrastructure integration without contaminating the domain layer.

## Frequently Asked Questions

### What is the primary purpose of separating bounded and unbounded models in DDDplus?

The separation prevents the accumulation of unrelated responsibilities into a single entity—the God-class anti-pattern—by isolating immutable core identity (`IUnboundedDomainModel`) from variable scenario-specific behaviors (`BoundedDomainModel`). This enables independent evolution of business contexts while maintaining a stable domain core.

### How does BoundedDomainModel access the core entity properties?

Each `BoundedDomainModel<T>` maintains a protected reference to its underlying unbounded model via the `protected T model` field, established through the constructor `super(model)`. This allows bounded implementations to access core identity attributes while extending functionality with context-specific methods.

### Can a single unbounded model support multiple bounded models simultaneously?

Yes, this is the intended design pattern. A single `IUnboundedDomainModel` implementation—such as a `User` entity—can serve as the foundation for multiple `BoundedDomainModel` instances (e.g., `Buyer`, `Contact`, `Debtor`), each modeling a distinct role or bounded context without interfering with one another.

### Where are IUnboundedDomainModel and BoundedDomainModel defined in the codebase?

The `IUnboundedDomainModel` interface and `BoundedDomainModel` abstract class are defined in `dddplus-spec/src/main/java/io/github/dddplus/model/`, specifically in [`IUnboundedDomainModel.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/IUnboundedDomainModel.java) and [`BoundedDomainModel.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/BoundedDomainModel.java) respectively. Unit tests illustrating usage patterns are available in [`dddplus-test/src/test/java/io/github/dddplus/model/BoundedDomainModelTest.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-test/src/test/java/io/github/dddplus/model/BoundedDomainModelTest.java).