Skip to content

Instantly share code, notes, and snippets.

@erichonorez
Created September 10, 2018 12:22
Show Gist options
  • Save erichonorez/d56ba0f2e33952045bd3274638311475 to your computer and use it in GitHub Desktop.
Save erichonorez/d56ba0f2e33952045bd3274638311475 to your computer and use it in GitHub Desktop.
package com.example.demo;
import lombok.Value;
/**
* This example implements event sourcing using with versioning. It uses
*
* Each version has its own event interface (e.g. {@link EventV1} and {@link EventV2}) that extends the {@link Event}.
*
* In order to apply {@link Event} on a {@link State} the visitor pattern is used. Each version also define its own visitor interface (e.g. {@link VisitorV1} and {@link VisitorV2}). All visitors are aggregated with the {@link Visitor} interface.
*
* Each versioned visitor has one method for each {@link Event} of the same version.
*
* For 2 versioned events this solution has :
* <ol>
* <li>12 types</li>
* <li>2 types for the state (not important for the solution)</li>
* </ol>
*
* The main drawback is that it is a heavy solution. Lot of code and mutable state (if we want to keep the visitor reusable)!
* The main advantage is that there is a compile time check when creating new event (impossible to miss something).
*/
public class EventSourcingV2 {
interface Event {
String getLoanApplicationReference();
void accept(Visitor visitor);
default String getVersion() {
return "V1";
}
}
interface EventV1 extends Event {
@Override
default String getVersion() {
return "V1";
}
}
@Value
static class CreatedV1 implements EventV1 {
private String loanApplicationReference;
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
@Value
static class GrantedV1 implements EventV1 {
private String loanApplicationReference;
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
interface EventV2 extends Event {
@Override
default String getVersion() {
return "V2";
}
}
@Value
static class CreatedV2 implements EventV2 {
private String loanApplicationReference;
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
@Value
static class GrantedV2 implements EventV2 {
private String loanApplicationReference;
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
interface VisitorV1 {
void visit(CreatedV1 e);
void visit(GrantedV1 e);
void visitAll(EventV1 eventV1);
}
interface VisitorV2 {
void visit(CreatedV2 e);
void visit(GrantedV2 e);
void visitAll(EventV2 eventV2);
}
interface Visitor extends VisitorV1, VisitorV2 {
}
interface State {
boolean isGranted();
}
@Value
static class Data implements State {
boolean isGranted;
}
static void apply(Event e, State s) {
e.accept(new Visitor() {
private VisitorImplV1 v1 = new EventSourcingV2.VisitorImplV1();
private VisitorImplV2 v2 = new EventSourcingV2.VisitorImplV2();
@Override
public void visit(CreatedV1 e) {
v1.visit(e);
}
@Override
public void visit(GrantedV1 e) {
v1.visit(e);
}
@Override
public void visitAll(EventV1 e) {
v1.visitAll(e);
}
@Override
public void visit(CreatedV2 e) {
v2.visit(e);
}
@Override
public void visit(GrantedV2 e) {
v2.visit(e);
}
@Override
public void visitAll(EventV2 e) {
v2.visitAll(e);
}
});
}
static class VisitorImplV1 implements VisitorV1 {
@Override
public void visit(CreatedV1 e) {
}
@Override
public void visit(GrantedV1 e) {
}
@Override
public void visitAll(EventV1 eventV1) {
}
}
static class VisitorImplV2 implements VisitorV2 {
@Override
public void visit(CreatedV2 e) {
}
@Override
public void visit(GrantedV2 e) {
}
@Override
public void visitAll(EventV2 eventV2) {
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment