Jack
Jack

Reputation: 182

I'm trying to implement an Observer Pattern on C#, want to know did I do it right way?

I'm very new on Observer Pattern, thought it very helpful in some cases, so I wrote a simple project, I'm not sure that I did it a right way or not, any suggestions will be appreciated.

class Program
    {
        public delegate void ProductAddedEventHandler(Object sender, ProductAddedEventArgs e);

        public class Products
        {
            private double subtotal;
            public event ProductAddedEventHandler ProductAdded;

            public void Add(Product product)
            {
                ProductModels model = new ProductModels();
                IEnumerable<Product> products = model.Products();
                IEnumerable<Product> new_Collection = products.Concat(new List<Product>() { product });

                Calculate calculate = new Calculate();
                this.subtotal = calculate.create(new_Collection);

                if (ProductAdded != null)
                {
                    ProductAddedEventArgs e = new ProductAddedEventArgs(subtotal);
                    ProductAdded(this, e);
                }

                Console.WriteLine("Subtotal Amount: {0}", subtotal);
            }
        }

        /// <summary>
        /// Calculate the Subtotal
        /// </summary>
        public class Calculate
        {
            public double create(IEnumerable<Product> products)
            {
                double result = 0;
                foreach (Product p in products)
                {
                    result += p.Price;
                }

                return result;
            }
        }

        public class ProductAddedEventArgs : EventArgs
        {
            public readonly double SubTotal;
            public ProductAddedEventArgs(double subtotal) => SubTotal = subtotal;
        }

        public class Shipping
        {
            const double Shipping_Rate = 0.05;

            public void create(Object sender, ProductAddedEventArgs e)
            {
                Console.WriteLine("Shipping Amount: {0}", e.SubTotal * Shipping_Rate);
            }
        }

        public class Discount
        {
            const double Discount_Rate = 0.2;
            public void create(Object sender, ProductAddedEventArgs e)
            {
                Console.WriteLine("Discount Amount: {0}", e.SubTotal * Discount_Rate);
            }
        }

        public class Tax
        {
            const double Tax_Rate = 0.07;

            public void create(Object sender, ProductAddedEventArgs e)
            {
                Console.WriteLine("Tax Amount: {0}", e.SubTotal * Tax_Rate);
            }
        }

        static void Main(string[] args)
        {

            Products products = new Products();
            Shipping shipping = new Shipping();
            Discount discount = new Discount();
            Tax tax = new Tax();

            products.ProductAdded += shipping.create;
            products.ProductAdded += discount.create;
            products.ProductAdded += tax.create;

            products.Add(new Product()
            {
                Id = 50,
                Name = "Watermelon",
                Price = 9.21
            });

        }
    }

BTW, How to get the total amount?

Upvotes: 0

Views: 282

Answers (1)

vendettamit
vendettamit

Reputation: 14677

Although this question belongs to https://codereview.stackexchange.com/ but i'll try to write a brief answer.

The definition of Observer pattern from DoFactory(GOF),

Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

In your example you have't defined any observer instead you have events that are changing the state of the object itself. And there are too many responsibility or work being done in Add() method.

The example of the Observer could be a shopping cart(e-commerce) e.g. When the products count is changed then the order summary object should know about it and re-calculate the summary(taxes, discount, total etc.). See below example for a Cart and Order Summary being updated as Observer of cart items. It is not perfect but it will give you a notion of Observer pattern:

class Product
{
    // Product properties
}

class ProductCollection
{
    private List<Observer> _observers = new List<Observer>();
    List<Product> _internalcol = new List<Product>();

    public void Attach(Observer observer)
    {
      _observers.Add(observer);
    }

    public void Detach(Observer observer)
    {
      _observers.Remove(observer);
    }

    public void Add(Product p)
    {
        _internalcol.Add(p)
        Notify();
    }

    public void Remove(Product p)
    {

    }

    private void Notify()
    {
      foreach (Observer o in _observers)
      {
        o.Update();
      }
    }
}

class Cart
{
    public ProductionCollection products = new ProductionCollection();
    public OrderSummary summary = new OrderSummary();

    public Cart()
    {
        products.Attach(new OrderSummary(products));
    }

    public void AddProduct(Product p, int count)
    {
        if(count > 1){
            foreach(int i in count){
                products.Add(p);
            }
        else if(count == 1){
            products.Add(p);
        }
        else if(count == 0)
        {
            products.Remove(p);
        }
    }
}

abstract class Observer()
{
    abstract void Update();
}

class OrderSummary: Observer
{
    ProductionCollection _products;

     // Constructor
    public OrderSummary(ProductionCollection products)
    {
        this._products = products;
    }

    public override void Update()
    {
      //Recalculate taxes, discount etc. here.
      // Update Summary object
    }

    public void GetSummary()
    {
        // return/print Summary object;
    }
}

class program
{
        static void Main(string[] args)
        {
            Cart c = new Cart();
            c.products.AddProduct(
                new Product()
                {
                    Id = 50,
                    Name = "Watermelon",
                    Price = 9.21
                });
        }
}

It may not compile I wrote it in Notepad.

Upvotes: 1

Related Questions