Sobes.tech
Senior

What is DCI?

sobes.tech AI

Answer from AI

DCI (Data-Context-Interaction) is an architectural pattern that focuses on how objects interact within a specific context to perform a certain action. It aims to improve code readability and maintainability by separating data (Data) from behavior within a context (Interaction), which acts upon them in a particular situation (Context).

  • Data: Represents the state of objects. These can be regular classes or structures containing data.
  • Context: Describes a specific situation or scenario in which object interactions occur. The context links participants (data objects) with roles.
  • Interaction: Defines the behavior or logic applied to the context participants. Interaction is implemented through roles that participants play within the context.

Advantages of DCI:

  • Improved readability: The code describing interaction is separated from data definitions, making it more understandable.
  • Reduction of code duplication: Behavior specific to a particular scenario is encapsulated, reducing the need to duplicate logic.
  • Increased flexibility: Easier to change or add new interaction scenarios without affecting data definitions.
  • Testability: Separate components (data, context, interactions) are easier to test in isolation.

Example (conceptual):

Let's consider a "money transfer" scenario between two bank accounts.

  • Data: A BankAccount class with fields balance and accountNumber.
  • Context: MoneyTransferContext which links two BankAccount objects with roles "Source" (sender) and "Destination" (receiver).
  • Interaction: The logic of transferring money: deducting from the sender's balance and adding to the receiver's balance. This logic is implemented through methods of roles "Source" and "Destination" within MoneyTransferContext.
// Conceptual code example (not a full DCI implementation)
class BankAccount {
  constructor(public balance: number, public accountNumber: string) {}

  // Methods specific to data
  getBalance(): number {
    return this.balance;
  }

  deposit(amount: number): void {
    this.balance += amount;
  }

  withdraw(amount: number): void {
    if (this.balance >= amount) {
      this.balance -= amount;
    } else {
      throw new Error("Insufficient funds");
    }
  }
}

// Context and interaction (mixed here for simplicity)
class MoneyTransferContext {
  constructor(private source: BankAccount, private destination: BankAccount) {}

  transfer(amount: number): void {
    try {
      // Interaction through roles (implicitly here)
      this.source.withdraw(amount);
      this.destination.deposit(amount);
      console.log(`Successfully transferred ${amount} from ${this.source.accountNumber} to ${this.destination.accountNumber}`);
    } catch (error: any) {
      console.error(`Failed to transfer money: ${error.message}`);
    }
  }
}

// Usage
const account1 = new BankAccount(1000, "123");
const account2 = new BankAccount(500, "456");

const transferContext = new MoneyTransferContext(account1, account2);
transferContext.transfer(200);
transferContext.transfer(1500); // Error due to insufficient funds

In real DCI, the interaction (the transfer logic) would be implemented in separate "role" methods, which are "injected" or "added" to BankAccount objects within the MoneyTransferContext, without changing the BankAccount class itself. This is achieved through various techniques depending on the programming language.