Skip to content

Instantly share code, notes, and snippets.

@texdc
Last active February 6, 2017 20:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save texdc/f541e54a8d384cd1dc7de738cb1fe3f5 to your computer and use it in GitHub Desktop.
Save texdc/f541e54a8d384cd1dc7de738cb1fe3f5 to your computer and use it in GitHub Desktop.
Assuming that Akka had a Dart SDK...
library ddd.account;
import 'account_event.dart';
import 'package:akka/akka.dart' show TypedActor;
class _AccountState {
static const String _UNKNOWN_ACCOUNT = 'unknown';
final String accountNumber;
final num balance;
bool get _isUnknown => accountNumber == _UNKNOWN_ACCOUNT;
_AccountState([this.accountNumber = _UNKNOWN_ACCOUNT, this.balance = 0]) {
if (accountNumber == null || accountNumber.trim().isEmpty()) {
throw new ArgumentError.value(accountNumber, 'accountNumber', 'Cannot be null or empty.');
}
if (balance == null || balance < 0) {
throw new ArgumentError.value(balance, 'balance', 'Cannot be null or less than 0.');
}
}
_AccountState open(String anAccountNumber, num anAmount) => _isUnknown ? new _AccountState(anAccountNumber, anAmount) : this;
_AccountState deposit(num anAmount) => _isUnknown ? this : new _AccountState(accountNumber, balance + anAmount);
_AccountState withdraw(num anAmount) => _isUnknown ? this : new _AccountState(accountNumber, balance - anAmount);
}
class Account extends TypedActor {
_AccountState _state;
String get accountNumber => _state.accountNumber;
num get balance => _state.balance;
bool get isOverdrawn => balance < 0;
Account(EventBus anEventBus, [this._state = new _AccountState()]) : super(anEventBus) {
events.when((event) => event is OpenAccount).listen(_open);
events.when((event) => event is DepositFunds).listen(_deposit);
events.when((event) => event is WithdrawFunds).listen(_withdraw);
}
Map<String, String> toMap() => {
'accountNumber' : accountNumber,
'balance' : balance.toString()
};
void _open(OpenAccount aCommand) {
if (!aCommand.requestorCanOpen) {
events.trigger(new OpenProhibited(aCommand.requestor));
return;
}
_state = _state.open(aCommand.accountNumber, aCommand.initialBalance);
events.trigger(new AccountOpened(accountNumber, balance)):
}
void _deposit(DepositFunds aCommand) {
if (!aCommand.requestorCanDeposit) {
events.trigger(new DepositProhibited(accountNumber, aCommand.amount));
return;
}
_state = _state.deposit(aCommand.amount);
events.trigger(new FundsDeposited(accountNumber, aCommand.amount));
}
void _withdraw(WithdrawFunds aCommand) {
if (balance <= 0 && !aCommand.requestorCanOverdraw) {
events.trigger(new WithdrawalProhibited(accountNumber, aCommand.amount));
return;
}
_state = _state.withdraw(aCommand.amount);
events.trigger(new FundsWithdrawn(accountNumber, aCommand.amount));
}
String toString() => '[Account] accountNumber: $accountNumber, balance: $balance';
}
library ddd.account.event;
abstract class AccountEvent {
final String accountNumber;
AccountEvent(this.accountNumber) {
if (accountNumber == null || accountNumber.trim().isEmpty) {
throw new ArgumentError.notNull('accountNumber');
}
}
}
class OpenAccount extends AccountEvent {
final num initialBalance;
final Role requestor;
bool get requestorCanOpen => requestor.canOpen;
OpenAccount(String anAccountNumber, this.initialBalance, this.requestor) : super(anAccountNumber) {
if (initialBalance == null || initialBalance < 0) {
throw new ArgumentError.notNull('initialBalance');
}
if (requestor == null) throw new ArgumentError.notNull('requestor');
}
}
class OpenProhibited {
final Role requestor;
OpenProhibited(this.requestor) {
if (requestor == null) throw new ArgumentError.notNull('requestor');
}
}
abstract class ProhibitionEvent extends AccountEvent {
final num amountRequested;
ProhibitionEvent(String anAccountNumber, this.amountRequested) : super(anAccountNumber) {
if (amountRequested == null) throw new ArgumentError.notNull('amountRequested');
}
}
class DepositProhibited extends ProhibitionEvent {
DepositProhibited(String anAccountNumber, num anAmountRequested) : super(anAccountNumber, anAmountRequested);
}
class WithdrawalProhibited extends ProhibitionEvent {
WithdrawalProhibited(String anAccountNumber, anAmountRequested) : super(anAccountNumber, anAmountRequested);
}
abstract class FundsCommand {
final num amount;
final Role requestor;
FundsCommand(this.amount, this.requestor) {
if (amount == null || amount < 0) {
throw new ArgumentError.notNull('amount');
}
if (requestor == null) throw new ArgumentError.notNull('requestor');
}
}
class DepositFunds extends FundsCommand {
bool get requestorCanDeposit => requestor.canDeposit;
DepositFunds(num anAmount, Role aRequestor) : super(anAmount, aRequestor);
}
class WithdrawFunds extends FundsCommand {
bool get requestorCanOverdraw => requestor.canOverdraw;
WithdrawFunds(num anAmount, Role aRequestor) : super(anAmount, aRequestor);
}
class AccountOpened extends AccountEvent {
final num initialBalance;
AccountOpened(String anAccountNumber, this.initialBalance) : super(anAccountNumber) {
if (initialBalance == null || initialBalance < 0) {
throw new ArgumentError.notNull('initialBalance');
}
}
}
abstract class FundsEvent extends AccountEvent {
final num amount;
FundsEvent(String anAccountNumber, this.amount) : super(anAccountNumber) {
if (amount == null || amount < 0) {
throw new ArgumentError.notNull('amount');
}
}
}
class FundsDeposited extends FundsEvent {
FundsDeposited(String anAccountNumber, num anAmount) : super(anAccountNumber, anAmount);
}
class FundsWithdrawn extends FundsEvent {
FundsWithdrawn(String anAccountNumber, num anAmount) : super(anAccountNumber, anAmount);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment