Imagine that we have an Aggregate that has a life cycle, such that it can change its behavior during its lifetime. During the first part of its life, it can do some things and during the second part, it can do other things.
I´d like to hear opinions on how should we restrict what the aggregate can do on each phase.
To make it a little more tangible, lets take an financial trade as an aggreagate example.
A trader creates a trade informing the contract, and its price.
A risk manager validates a trade, giving a reason for such.
The BackOffice can submit the trade to the ledger, providing accounting information.
After the trade is submitted, the accounting information can never be changed.
The trade clearly has 3 distinct phases, which I´ll call Typed, Validated and Submitted
My first thought is to pollute the aggregate with InvalidOperationExceptions, which I really don´t like:
public class Trade
{
private enum State { Typed, Validated, Submited }
private State _state = State.Typed;
public Guid Id { get; }
public Contract Contract { get; }
public decimal Price { get; }
public Trade (Guid id, Contract contract, decimal price) { ... }
private string _validationReason = null;
private AccountingInformation _accInfo = null;
public void Validate(string reason) {
if (_state != State.Typed)
throw new InvalidOperationException (..)
...
_validationReason = reason;
_state = State.Validated;
}
public string GetValidationReason() {
if (_state == State.Typed)
throw new InvalidOperationException (..)
return _validationReason;
}
public void SubmitToLedger(AccountingInformation info) {
if ((_state != State.Validated))
throw new InvalidOperationException (..)
...
}
public AccountingInfo GetAccountingInfo() { .. }
}
I can do something like a Maybe pattern, to avoid the exceptions on the Get... methods. But that would not work for the behavior methods (Validate, SubmitToLedger, etc)
Oddly, if I were to be working on a functional language (such as F#), I would probably create a different type for each state.
type TypedTrade = { Id : Guid; Contract: Contract; Price : decimal }
type ValidatedTrade = { Id : Guid;
Contract: Contract;
Price : decimal;
ValidationReason : string}
type SubmittedTrade = { Id : Guid;
Contract: Contract;
Price : decimal;
ValidationReason : string;
AccInfo : AccountingInfo }
// TypedTrade -> string -> ValidatedTrade
let validateTrade typedTrade reason =
...
{ Id = typedTrade.Id; Contract = typedTrade.Contract;
Price = typedTrade.Price; Reason = reason }
// ValidatedTrade -> AccountingInfo -> SubmittedTrade
let submitTrade validatedTrade accInfo =
...
{ Id = validatedTrade.Id;
Contract = validatedTrade.Contract;
Price = validatedTrade.Price;
Reason = validatedTrad.Reason;
AccInfo = accInfo }
And the problem would gracefully go away. But to do that in OO, I would have to make my aggregate immutable and maybe create some kind o hierarchy (in which I would have to hide base methods !? ouch!).
I just wanted an opinion on what you guys do on these situations, and if there is a better way.
I like the idea of having different types for each state. Its a clean design in my opinion. From a logical view a newly created trade is definitly something different than a submitted trade.
public Interface ITrade
{
Guid Id { get; }
Contract Contract { get; }
decimal Price { get; }
}
public class Trade : ITrade
{
public Trade(Guid id, Contract contract, decimal price)
{
Id = id;
Contract = contract;
Price = price;
}
Guid Id { get; }
Contract Contract { get; }
decimal Price { get; }
public ValidatedTrade Validate(string reason)
{
return new ValidatedTrade(this, reason);
}
}
public class ValidatedTrade : ITrade
{
private ITrade trade;
private string validationReason;
public ValidatedTrade(Trade trade, string validationReason)
{
this.trade = trade;
this.validationReason = validationReason;
}
Guid Id { get { return trade.Id; } }
Contract Contract { get { return trade.Contract ; } }
decimal Price { get { return trade.Price ; } }
public string GetValidationReason()
{
return validationReason;
}
public SubmittedTrade SubmitToLedger(AccountingInfo accountingInfo)
{
return new SubmittedTrade(this, accountingInfo);
}
}
public class SubmittedTrade : ITrade
{
private ITrade trade;
private AccountingInfo accountingInfo;
public SubmittedTrade(ValidatedTrade trade, AccountingInfo accountingInfo)
{
this.trade = trade;
this.accountingInfo = accountingInfo;
}
Guid Id { get { return trade.Id; } }
Contract Contract { get { return trade.Contract ; } }
decimal Price { get { return trade.Price ; } }
public AccountingInfo GetAccountingInfo() { .. }
}
You could have one class per state instead of a single class. See this post by Greg Young : http://codebetter.com/gregyoung/2010/03/09/state-pattern-misuse/
The usual problem with the State pattern is the friction with persistence concerns and especially ORMs. It's up to you to decide if the better robustness and type safety is worth the trouble.
Related
Currently, I'm working on the Order Microservice, where I have two methods related to order status changes store(Order order) and updateStatus(int orderId, String status), I'll explain later.
There are four states of the Order:
Waiting -> Expired
Waiting -> Canceled
Waiting -> Purchased
Purchased -> Canceled
I've provided the state flow diagram below, to make it clear (hopefully)
When the order created then the status will be "Waiting", if the user has paid it then the status becomes "Purchased", if the buyer or product owner cancel it then the status becomes "Canceled", and if the time exceeded then the status becomes "Expired".
For every microservice I want to work on, I'll be implementing Gang Of Four design pattern if possible, and for the order status I decided to implement state design pattern since it is related and from what I refer in many blogs, like in the document status stuff (DRAFT, ON REVIEW, etc), audio player stuff (PAUSED, PLAYED, etc) and so on.
This is what I've done:
Base State
public interface OrderStatus {
void updateStatus(OrderContext orderContext);
}
Waiting state
public class WaitingState implements OrderStatus {
// omited for brevity
#Override
public void updateStatus(OrderContext orderContext) {
orderContext.getOrder().setStatus("Waiting");
}
}
Purchased State
public class PurchasedState implements OrderStatus {
// omited for brevity
#Override
public void updateStatus(OrderContext orderContext) {
orderContext.getOrder().setStatus("Purchased");
}
}
Other states
..
Context:
public class OrderContext {
private OrderStatus currentStatus;
private Order order;
public OrderContext(OrderStatus currentStatus, Order order) {
this.currentStatus = currentStatus;
this.order = order;
}
public void updateState() {
currentStatus.updateStatus(this);
}
public OrderStatus getCurrentStatus() {
return currentStatus;
}
public void setCurrentStatus(OrderStatus currentStatus) {
this.currentStatus = currentStatus;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}
The client is the OrderServiceImpl which I called from OrderController.
public class OrderServiceImpl implements OrderService {
// omited for brevity
#Override
public Order store(Order order) {
WaitingState state = WaitingState.getInstance();
OrderContext context = new OrderContext(state, order);
context.updateState();
// do other stuff
}
#Override
public void updateStatus(int orderId, String status) {
Order order = orderRepository.findById(id);
// but how about this?? this still requires me to use if/else or switch
}
}
As you can see, I can do it while creating the Order in the store(Order order) method, but I have no idea to do it in updateStatus(int orderId, String status) since it is still required to check status value to use the right state.
switch (status) {
case "EXPIRED": {
ExpiredState state = ExpiredState.getInstance();
OrderContext context = new OrderContext(state, order);
context.updateState();
// do something
break;
}
case "CANCELED": {
CanceledState state = CanceledState.getInstance();
OrderContext context = new OrderContext(state, order);
context.updateState();
// do something
break;
}
// other case
default:
// do something
break;
}
The exact reason to implement the state design pattern is to minimize "the switch stuff/hardcoded checking" and the flexibility for adding more state without breaking current code (Open/Close principle), but maybe I'm wrong, maybe I'm lack of knowledge, maybe I'm too naive to decide to use this pattern.
But at the end of the day, I found out that I still need to use the switch stuff to use the state pattern.
Then, what's the right way to handle the order status changes?
The exact reason to implement the state design pattern is to minimize "the switch stuff/hardcoded checking" and the flexibility for adding more state without breaking current code (Open/Close principle)
Polymorphism does not replace all conditional logic.
but maybe I'm wrong, maybe I'm lack of knowledge, maybe I'm too naive to decide to use this pattern.
Consider what behaviors actually change in response to an order's status change. If no behaviors change, there's no reason to use the State pattern.
For example, if the order's behavior does not change, assigning an integer (or enum) or string as an order status is fine:
enum OrderStatus {
WAITING,
CANCELLED,
EXPIRED,
PURCHASED
}
class Order {
private OrderStatus status;
public Order() {
status = OrderStatus.WAITING;
}
public void setStatus(OrderStatus s) {
status = s;
}
public void doOperation1() {
System.out.println("order status does not affect this method's behavior");
}
public void doOperation2() {
System.out.println("order status does not affect this method's behavior");
}
public void doOperation3() {
System.out.println("order status does not affect this method's behavior");
}
}
If doOperation()s remain the same despite status changes, this code works fine.
However, real problems start to occur when doOperation()s' behaviors change due to status changes. What you'll end up with is methods that look like this:
...
public void doOperation3() {
switch (status) {
case OrderStatus.WAITING:
// waiting behavior
break;
case OrderStatus.CANCELLED:
// cancelled behavior
break;
case OrderStatus.PURCHASED:
// etc
break;
}
}
...
For many operations, this is unmaintainable. Adding more OrderStatus will become complex and affect many Order operations, violating the Open/Closed Principal.
The State pattern is meant to address this problem specifically. Once you identify which behaviors change, you extract them to an interface. Let's imagine doOperation1() changes:
interface OrderStatus {
void doOperation1();
}
class WaitingOrderStatus implements OrderStatus {
public void doOperation1() {
System.out.println("waiting: doOperation1()");
}
public String toString() {
return "WAITING";
}
}
class CancelledOrderStatus implements OrderStatus {
public void doOperation1() {
System.out.println("cancelled: doOperation1()");
}
public String toString() {
return "CANCELLED";
}
}
class Order implements OrderStatus {
private OrderStatus status;
public Order() {
status = new WaitingOrderStatus();
}
public void setStatus(OrderStatus s) {
status = s;
}
public void doOperation1() {
status.doOperation1();
}
public void doOperation2() {
System.out.println("order status does not affect this method's behavior");
}
public void doOperation3() {
System.out.println("order status does not affect this method's behavior");
}
}
class Code {
public static void main(String[ ] args) {
Order o = new Order();
o.doOperation1();
}
}
Adding new states is easy and it adheres to the Open/Closed Principal.
I have an abstract class Payment, which is implemented by several PaymentTypes
public abstract class Payment
{
protected int contract;
public Payment(int contract)
{
this.contract = contract;
}
public abstract bool Aprove();
}
and then, two classes which implement it
public class PaymentA : Payment
{
public PaymentA(int contract) : base(contract)
{
this.contract = contract;
}
public override bool Aprove()
{
return true;
}
}
public class PaymentB : Payment
{
public PaymentB(int contract) : base(contract)
{
this.contract = contract;
}
public override bool Aprove()
{
return true;
}
}
Now, I need to create PaymentA or PaymentB depending on a form field
static void Main(string[] Args)
{
int contract = 1;
Payment payment;
switch (rbtPaymentType)
{
case (int)EPaymentTypes.A:
payment = new PaymentA(contract);
break;
case (int)EPaymentTypes.B:
payment = new PaymentB(contract);
break;
}
payment.Aprove(); //Use of unassigned local variable
}
I have two questions:
1 - Is it well constructed so I can call payment.Aprove() no matter which type of payment it is?
2 - How can I do the method call if the object is not initialized? I get error "Use of unassigned local variable"
Thanks in advance
1 - Is it well constructed so I can call payment.Aprove() no matter which type of payment it is?
Yes, for simple application it's ok. If you want to make it a little better you can use simple factory like so:
public class PaymentFactory
{
public Payment CreatePayment(int rbtPaymentType, int contract)
{
switch (rbtPaymentType)
{
case (int)EPaymentTypes.A:
return new PaymentA(contract);
case (int)EPaymentTypes.B:
return new PaymentB(contract);
default:
throw new Exception("Unknown payment type");
}
}
}
class Program
{
static void Main(string[] Args)
{
int contract = 1;
Payment payment = null;
int rbtPaymentType = 1;
PaymentFactory paymentFactory = new PaymentFactory();
payment = paymentFactory.CreatePayment(rbtPaymentType, contract);
payment.Aprove();
}
}
Whenever you switch over something to create a new instance you should think about encapsulating it in factory. This way you don't have to repeat the same switch in other place if you want to create another instance of Payment.
2 - How can I do the method call if the object is not initialized? I get error "Use of unassigned local variable"
You can assign it to null like I've shown in the example above.
Btw. you don't have to assign contract member in constructors of PaymentA and PaymentB since base class does it for you.
I am reading Test Driven Development: By Example. I am on chapter 13. Chapter 12 and 13 introduced Plus operation to Money object. A Money object can plus by other Money object.
The author added two classes (Bank and Sum) and one interface (IExpression) to the solution. This is the class diagram of the final solution.
Money store amount and currency for example 10 USD, 5 BAHT, 20 CHF. The Plus method returns Sum object.
public class Money : IExpression
{
private const string USD = "USD";
private const string CHF = "CHF";
public int Amount { get; protected set; }
public string Currency { get; private set; }
public Money(int value, string currency)
{
this.Amount = value;
this.Currency = currency;
}
public static Money Dollar(int amount)
{
return new Money(amount, USD);
}
public static Money Franc(int amount)
{
return new Money(amount, CHF);
}
public Money Times(int times)
{
return new Money(this.Amount * times, this.Currency);
}
public IExpression Plus(Money money)
{
return new Sum(this, money);
}
public Money Reduce(string to)
{
return this;
}
public override bool Equals(object obj)
{
var money = obj as Money;
if (money == null)
{
throw new ArgumentNullException("obj");
}
return this.Amount == money.Amount &&
this.Currency == money.Currency;
}
public override string ToString()
{
return string.Format("Amount: {0} {1}", this.Amount, this.Currency);
}
}
Sum store two Money objects which come from constructor arguments. It has one method Reduce that return new Money object (create new object by add amount of two object)
public class Sum : IExpression
{
public Money Augend { get; set; }
public Money Addend { get; set; }
public Sum(Money augend, Money addend)
{
this.Augend = augend;
this.Addend = addend;
}
public Money Reduce(string to)
{
var amount = this.Augend.Amount + this.Addend.Amount;
return new Money(amount, to);
}
}
Bank has one method - Reduce. It just call Reduce method of incoming IExpression argument.
public class Bank
{
public Money Reduce(IExpression source, string to)
{
return source.Reduce(to);
}
}
IExpression is an interface that implemented by Money and Sum.
public interface IExpression
{
Money Reduce(string to);
}
These are my questions.
Bank does nothing good for the solution at this stage. Why do I need it?
Why do I need Sum since I can create and return Money object inside Plus of the class Money (Like what the author did with Times)?
What is the purpose of Bank and Sum? (Right now, it doesn't make any sense for me)
I think Reduce sound strange for me as the method name. Do you think it is a good name? (please suggest)
Keep reading. Kent Beck is a very smart guy. He either has a very good reason why he created the example that way, and it will be clear later on, or it's a poor solution.
"Reduce" is a very good name if map-reduce is the ultimate goal.
I wonder how to add state to the chain of decorators that will be available to the consumer. Given this simplified model:
abstract class AbstractPizza
{
public abstract print(...);
}
class Pizza : AbstractPizza
{
public int Size { get; set; }
public print(...);
}
abstract class AbstractPizzaDecorator
{
public Pizza:AbstractPizza;
public abstract print();
}
class HotPizzaDecorator : AbstractPizzaDecorator
{
public int Hotness { get; set; }
public print(...);
}
class CheesyPizzaDecorator : AbstractPizzaDecorator
{
public string Cheese { get; set; }
public print(...);
}
void Main()
{
BigPizza = new Pizza();
BigPizza.Size = 36;
HotBigPizza = new HotPizzaDecorator();
HotBigPizza.Pizza = BigPizza;
HotBigPizza.Hotness = 3;
HotBigCheesyPizza = new CheesyPizzaDecorator();
HotBigCheesyPizza.Pizza = HotBigPizza;
HotBigCheesyPizza.Cheese = "Blue";
HotBigCheesyPizza.print();
HotBigCheesyPizza.size = 28; // ERRRRRR !
}
Now if they all implement the print method and propagate that though the chain, it's all good. But how does that work for the state? I can't access the size property on the HotBigCheesyPizza.
What's the part that I'm missing? Wrong pattern?
Thanks for helping!
Cheers
The decorator pattern is for adding additional behavior to the decorated class without the client needing to adjust. Thus it is not intended for adding a new interface (e.g. hotness, cheese) to the thing being decorated.
A somewhat bad example of what it might be used for is where you want to change how size is calculated: you could create a MetricSizePizzaDecorator that converts the size to/from English/metric units. The client would not know the pizza has been decorated - it just calls getSize() and does whatever it needs to do with the result (for example, to calculate the price).
I would probably not use the decorator in my example, but the point is: it does not alter the interface. In fact, nearly all design patterns come down to that - adding variability to a design without changing interfaces.
one way of adding state is by using a self referential data structure (a list). but this uses the visitor pattern and does more than you probably want. this code is rewritten from A little Java, a few patterns
// a self referential data structure with different types of nodes
abstract class Pie
{
abstract Object accept(PieVisitor ask);
}
class Bottom extends Pie
{
Object accept(PieVisitor ask) { return ask.forBottom(this); }
public String toString() { return "crust"; }
}
class Topping extends Pie
{
Object topping;
Pie rest;
Topping(Object topping,Pie rest) { this.topping=topping; this.rest=rest; }
Object accept(PieVisitor ask) { return ask.forTopping(this); }
public String toString() { return topping+" "+rest.toString(); }
}
//a class to manage the data structure
interface PieManager
{
int addTopping(Object t);
int removeTopping(Object t);
int substituteTopping(Object n,Object o);
int occursTopping(Object o);
}
class APieManager implements PieManager
{
Pie p=new Bottom();
// note: any object that implements a rational version of equal() will work
public int addTopping(Object t)
{
p=new Topping(t,p);
return occursTopping(t);
}
public int removeTopping(Object t)
{
p=(Pie)p.accept(new RemoveVisitor(t));
return occursTopping(t);
}
public int substituteTopping(Object n,Object o)
{
p=(Pie)p.accept(new SubstituteVisitor(n,o));
return occursTopping(n);
}
public int occursTopping(Object o)
{
return ((Integer)p.accept(new OccursVisitor(o))).intValue();
}
public String toString() { return p.toString(); }
}
//these are the visitors
interface PieVisitor
{
Object forBottom(Bottom that);
Object forTopping(Topping that);
}
class OccursVisitor implements PieVisitor
{
Object a;
OccursVisitor(Object a) { this.a=a; }
public Object forBottom(Bottom that) { return new Integer(0); }
public Object forTopping(Topping that)
{
if(that.topping.equals(a))
return new Integer(((Integer)(that.rest.accept(this))).intValue()+1);
else return that.rest.accept(this);
}
}
class SubstituteVisitor implements PieVisitor
{
Object n,o;
SubstituteVisitor(Object n,Object o) { this.n=n; this.o=o; }
public Object forBottom(Bottom that) { return that; }
public Object forTopping(Topping that)
{
if(o.equals(that.topping))
that.topping=n;
that.rest.accept(this);
return that;
}
}
class RemoveVisitor implements PieVisitor
{
Object o;
RemoveVisitor(Object o) { this.o=o; }
public Object forBottom(Bottom that) { return new Bottom(); }
public Object forTopping(Topping that)
{
if(o.equals(that.topping))
return that.rest.accept(this);
else return new Topping(that.topping,(Pie)that.rest.accept(this));
}
}
public class TestVisitor
{
public static void main(String[] args)
{
// make a PieManager
PieManager pieManager=new APieManager();
// add some toppings
pieManager.addTopping(new Float(1.2));
pieManager.addTopping(new String("cheese"));
pieManager.addTopping(new String("onions"));
pieManager.addTopping(new String("cheese"));
pieManager.addTopping(new String("onions"));
pieManager.addTopping(new String("peperoni"));
System.out.println("pieManager="+pieManager);
// substitute anchovies for onions
int n=pieManager.substituteTopping(new String("anchovies"),new String("onions"));
System.out.println(n+" pieManager="+pieManager);
// remove the 1.2's
n=pieManager.removeTopping(new Float(1.2));
System.out.println(n+" pieManager="+pieManager);
// how many anchovies do we have?
System.out.println(pieManager.occursTopping(new String("anchovies"))+" anchovies");
}
}
I believe your component Pizza and your abstract decorator PizzaDecorator are supposed to share the same interface, that way each instance of the decorator is capable of the same operations as the core component Pizza.
One day I decided to build this nice multi-tier application using L2S and WCF.
The simplified model is : DataBase->L2S->Wrapper(DTO)->Client Application.
The communication between Client and Database is achieved by using Data Transfer Objects which contain entity objects as their properties.
abstract public class BaseObject
{
public virtual IccSystem.iccObjectTypes ObjectICC_Type
{
get { return IccSystem.iccObjectTypes.unknownType; }
}
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_ID", AutoSync = AutoSync.OnInsert, DbType = "BigInt NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)]
[global::System.Runtime.Serialization.DataMemberAttribute(Order = 1)]
public virtual long ID
{
//get;
//set;
get
{
return _ID;
}
set
{
_ID = value;
}
}
}
[DataContract]
public class BaseObjectWrapper<T> where T : BaseObject
{
#region Fields
private T _DBObject;
#endregion
#region Properties
[DataMember]
public T Entity
{
get { return _DBObject; }
set { _DBObject = value; }
}
#endregion
}
Pretty simple, isn't it?. Here's the catch. Each one of the mapped classes contains ID property itself so I decided to override it like this
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Divisions")]
[global::System.Runtime.Serialization.DataContractAttribute()]
public partial class Division : INotifyPropertyChanging, INotifyPropertyChanged
{
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ID", AutoSync=AutoSync.OnInsert, DbType="BigInt NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
[global::System.Runtime.Serialization.DataMemberAttribute(Order=1)]
public override long ID
{
get
{
return this._ID;
}
set
{
if ((this._ID != value))
{
this.OnIDChanging(value);
this.SendPropertyChanging();
this._ID = value;
this.SendPropertyChanged("ID");
this.OnIDChanged();
}
}
}
}
Wrapper for division is pretty straightforward as well:
public class DivisionWrapper : BaseObjectWrapper<Division>
{
}
It worked pretty well as long as I kept ID values at mapped class and its BaseObject class the same(that's not very good approach, I know, but still) but then this happened:
private CentralDC _dc;
public bool UpdateDivision(ref DivisionWrapper division)
{
DivisionWrapper tempWrapper = division;
if (division.Entity == null)
{
return false;
}
try
{
Table<Division> table = _dc.Divisions;
var q = table.Where(o => o.ID == tempWrapper.Entity.ID);
if (q.Count() == 0)
{
division.Entity._errorMessage = "Unable to locate entity with id " + division.Entity.ID.ToString();
return false;
}
var realEntity = q.First();
realEntity = division.Entity;
_dc.SubmitChanges();
return true;
}
catch (Exception ex)
{
division.Entity._errorMessage = ex.Message;
return false;
}
}
When trying to enumerate over the in-memory query the following exception occurred:
Class member BaseObject.ID is unmapped.
Although I'm stating the type and overriding the ID property L2S fails to work.
Any suggestions?
Suppose I found the problem.
When writing
var q = table.Where(o => o.ID == tempWrapper.Entity.ID);
the compiler implies that the object is of BaseObject type and therefore tries to get its ID value from the BaseObject mapping and it's unmapped.
The problem seems to be resolved by explicitly declaring the type:
var q = from Division div in _dc.GetTable<Division>()
where div.ID == tempWrapper.Entity.ID
select div;