Czym jest DCI?
sobes.tech AI
Odpowiedź od AI
DCI (Data-Context-Interaction) to wzorzec architektoniczny, który koncentruje się na tym, jak obiekty wchodzą w interakcję w określonym kontekście, aby wykonać określone działanie. Ma na celu poprawę czytelności i utrzymania kodu, oddzielając dane (Data) od zachowania w kontekście (Interaction), które działa na nich w określonej sytuacji (Context).
- Data (Dane): Reprezentuje stan obiektów. Mogą to być zwykłe klasy lub struktury zawierające dane.
- Context (Kontekst): Opisuje konkretną sytuację lub scenariusz, w którym dochodzi do interakcji obiektów. Kontekst łączy uczestników (obiekty danych) z rolami.
- Interaction (Interakcja): Definiuje zachowanie lub logikę stosowaną do uczestników kontekstu. Interakcja realizowana jest przez role, które odgrywają uczestnicy w tym kontekście.
Zalety DCI:
- Lepsza czytelność: Kod opisujący interakcję jest oddzielony od definicji danych, co czyni go bardziej zrozumiałym.
- Redukcja duplikacji kodu: Zachowanie specyficzne dla scenariusza jest enkapsulowane, co zmniejsza konieczność duplikowania logiki.
- Większa elastyczność: Łatwiej jest modyfikować lub dodawać nowe scenariusze interakcji bez zmiany definicji danych.
- Testowalność: Oddzielne komponenty (dane, kontekst, interakcje) są łatwiejsze do testowania w izolacji.
Przykład (konceptualny):
Wyobraźmy sobie scenariusz "przelewu pieniędzy" między dwoma kontami bankowymi.
- Data: Klasa
BankAccountz polamibalanceiaccountNumber. - Kontekst:
MoneyTransferContext, który łączy dwa obiektyBankAccountz rolami "Source" (nadawca) i "Destination" (odbiorca). - Interakcja: Logika przelewu pieniędzy: odjęcie od salda nadawcy i dodanie do salda odbiorcy. Ta logika jest realizowana przez metody ról "Source" i "Destination" w ramach
MoneyTransferContext.
// Przykład kodu koncepcyjnego (niepełna implementacja DCI)
class BankAccount {
constructor(public balance: number, public accountNumber: string) {}
// Metody specyficzne dla danych
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("Niewystarczające środki");
}
}
}
// Kontekst i interakcja (tutaj wymieszane dla prostoty)
class MoneyTransferContext {
constructor(private source: BankAccount, private destination: BankAccount) {}
transfer(amount: number): void {
try {
// Interakcja przez role (niejawnie tutaj)
this.source.withdraw(amount);
this.destination.deposit(amount);
console.log(`Pomyślnie przelano ${amount} z ${this.source.accountNumber} do ${this.destination.accountNumber}`);
} catch (error: any) {
console.error(`Nieudany transfer pieniędzy: ${error.message}`);
}
}
}
// Użycie
const account1 = new BankAccount(1000, "123");
const account2 = new BankAccount(500, "456");
const transferContext = new MoneyTransferContext(account1, account2);
transferContext.transfer(200);
transferContext.transfer(1500); // Błąd z powodu niewystarczających środków
W prawdziwym DCI, interakcja (logika transfer) byłaby realizowana w oddzielnych metodach "ról", które "wstrzykuje się" lub "dodaje" do obiektów BankAccount w kontekście MoneyTransferContext, nie zmieniając samej klasy BankAccount. Jest to osiągane różnymi technikami w zależności od języka programowania.