Loading

CQRS+EventSourcing Exampl

  1.     private interface AccountEvent {
  2.         void match(final Listener listener);
  3.  
  4.         interface Listener {
  5.             void on(final MoneyCredited event);
  6.             void on(final MoneyDebited event);
  7.  
  8.             default void trigger(final AccountEvent event) {
  9.                 event.match(this);
  10.             }
  11.  
  12.             default void projection(final Collection<AccountEvent> events) {
  13.                 events.forEach(this::trigger);
  14.             }
  15.         }
  16.  
  17.         final class MoneyCredited implements AccountEvent {
  18.             private final Long amount;
  19.             MoneyCredited(final Long amount) { this.amount = amount; }
  20.  
  21.             public void match(final Listener listener) { listener.on(this); }
  22.         }
  23.  
  24.         final class MoneyDebited implements AccountEvent {
  25.             private final Long amount;
  26.             MoneyDebited(final Long amount) { this.amount = amount; }
  27.  
  28.             public void match(final Listener listener) { listener.on(this); }
  29.         }
  30.     }
  31.  
  32.     private interface AccountCommand {
  33.         void match(final Handler cases);
  34.  
  35.         interface Handler {
  36.             void handle(final DepositMoney command);
  37.             void handle(final WithdrawMoney command);
  38.         }
  39.  
  40.         final class DepositMoney implements AccountCommand {
  41.             private final Long amount;
  42.             DepositMoney(Long amount) { this.amount = amount; }
  43.  
  44.             public void match(final Handler handler) { handler.handle(this); }
  45.         }
  46.  
  47.         final class WithdrawMoney implements AccountCommand {
  48.             private final Long amount;
  49.             WithdrawMoney(final Long amount) { this.amount = amount; }
  50.  
  51.             public void match(final Handler handler) { handler.handle(this); }
  52.         }
  53.     }
  54.  
  55.     private class Account implements AccountCommand.Handler, AccountEvent.Listener {
  56.         private Long balance;
  57.  
  58.         private Account() {
  59.             this.balance = 0L;
  60.         }
  61.  
  62.         public Long getBalance() {
  63.             return balance;
  64.         }
  65.  
  66.         public void handle(final AccountCommand.DepositMoney command) {
  67.             trigger(new AccountEvent.MoneyCredited(command.amount));
  68.         }
  69.  
  70.         public void handle(final AccountCommand.WithdrawMoney command) {
  71.             if (balance - command.amount < 0) {
  72.                 System.out.printf("unable to withdraw %d from account with balance %d\n", command.amount, balance);
  73.                 return;
  74.             }
  75.             trigger(new AccountEvent.MoneyDebited(command.amount));
  76.         }
  77.  
  78.         public void on(final AccountEvent.MoneyCredited event) {
  79.             this.balance += event.amount;
  80.         }
  81.  
  82.         public void on(final AccountEvent.MoneyDebited event) {
  83.             this.balance -= event.amount;
  84.         }
  85.     }
  86.  
  87.  
  88.     @Test
  89.     public void test() {
  90.         final Account account = new Account();
  91.  
  92.         account.handle(new AccountCommand.DepositMoney(10L));
  93.         account.handle(new AccountCommand.DepositMoney(10L));
  94.         account.handle(new AccountCommand.DepositMoney(10L));
  95.         account.handle(new AccountCommand.DepositMoney(10L));
  96.         account.handle(new AccountCommand.DepositMoney(10L));
  97.         account.handle(new AccountCommand.WithdrawMoney(25L));
  98.  
  99.         assertThat(account.getBalance()).isEqualTo(25L);
  100.     }
  101.  
  102.     @Test
  103.     public void test2() {
  104.         final Account account = new Account();
  105.  
  106.         account.handle(new AccountCommand.DepositMoney(10L));
  107.         account.handle(new AccountCommand.DepositMoney(10L));
  108.         account.handle(new AccountCommand.DepositMoney(10L));
  109.         account.handle(new AccountCommand.DepositMoney(10L));
  110.         account.handle(new AccountCommand.DepositMoney(10L));
  111.         account.handle(new AccountCommand.WithdrawMoney(25L));
  112.  
  113.         account.handle(new AccountCommand.WithdrawMoney(26L));
  114.  
  115.         assertThat(account.getBalance()).isEqualTo(25L);
  116.     }
  117.  
  118.     @Test
  119.     public void test3() {
  120.         final Account account = new Account();
  121.  
  122.         final List<AccountEvent> events = new ArrayList<>();
  123.         events.add(new AccountEvent.MoneyCredited(10L));
  124.         events.add(new AccountEvent.MoneyCredited(10L));
  125.         events.add(new AccountEvent.MoneyCredited(10L));
  126.         events.add(new AccountEvent.MoneyCredited(10L));
  127.         events.add(new AccountEvent.MoneyCredited(10L));
  128.         events.add(new AccountEvent.MoneyDebited(25L));
  129.  
  130.         account.projection(events);
  131.  
  132.         assertThat(account.getBalance()).isEqualTo(25L);
  133.     }