I have a web application which has a shopping cart with cart items. The cart items are added to the user session, so must be serializable.I have a checkout class which takes the cart items and saves them in the DB. There are some special types of cart items however which will require pre and post processing actions, for example, one of my cart items may be an event ticket, meaning that after purchase I must actually generate and save the ticket.The question is, how do I add the logic of one module (ticket generation) to a completely unrelated module (shopping cart), while ensuring that the shopping cart is unaware of the existence of ticket generation, thus avoiding pollution of the domain.For example:interface ICartItem {  int quantity;  decimal amount;  string name;  // this interface has only checkout related  // data, no ticket related data}class Checkout {  void addCartItem(ICartItem cartItem) {    session.cartItems.Add(cartItem);  }  void doCheckout() {    foreach (var item in session.cartItems) {      saveCartItem(item);      // Now, somehow determine if the cart item is a       // ticket and if so save the ticket details    }  }}Note:My backup plan is this:interface ICartItem {  int quantity;  decimal amount;  string name;  // add ticket generation logic here and call it   // in the DoCheckout method  void onCheckoutComplete();}However, the organisation I am doing this for has a stack made of spaghetti, and it may be difficult to ensure that the ICartItem onCheckoutComplete() method will be called in all scenarios (present and future).
Design patterns to limit cross module logic
design patterns;domain model;modules