AspBucket offers ASP.NET, C#, VB, Jquery, CSS, Ajax, SQL tutorials. It is the best place for programmers to learn

Sunday 1 April 2018

Visitor Design Pattern in c#

Visitor pattern is a part of behavioral design pattern. Visitor pattern will not change the current code  structure It is used to add the new functionality in existing code. Classes which holds the new behaviors are commonly known as Visitors.

Visitor pattern promotes code separation, single responsibility principle & it also enforce the Open Close Principle.


Key Participants
  • Visitor - It declares a Visit operation for each class of ConcreteElement in the object structure. The operation's name and signature identifies the class. 
  • ConcreteVisitor -It implements each operation declared by Visitor.
  • Element- It defines an Accept operation that takes a visitor as an argument.
  • ConcreteElement -It implements an Accept operation that takes a visitor as an argument.
  • ObjectStructure- It holds all the element of the data structure as a collection, list or something which can be enumerated and used by the visitors. 
Code Sample

Let's take an example Where a program will calculate the price and quantity Food. Now You may find yourself in a situation where you need to make a functional change in price and quantity to a collection of classes but you do not have control over the classes in the hierarchy. This is where the Visitor pattern comes in. The intent of the Visitor design pattern is to define a new operation for a collection of classes (that is the classes being visited) without changing the hierarchy itself.

Here food price should increase by 10% and quantity need to increase by  3.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace VisitorPattern.Sample
{
    class Program
    {
        /// <summary>
        /// Entry point into console application.
        /// </summary>
        static void Main()
        {
            // Setup food collection
            var food = new FastFood();
            food.Attach(new Pizza());
            food.Attach(new Pasta());
            food.Attach(new Burger());

            // food are 'visited'
            food.Accept(new PriceVisitor());
            food.Accept(new QuantityVisitor());

            // Wait for user
            Console.ReadKey();
        }
    }

    /// <summary>
    /// The 'Visitor' abstract class
    /// </summary>
    public abstract class Visitor
    {
        // Use reflection to see if the Visitor has a method 
        // named Visit with the appropriate parameter type 
        // (i.e. a specific Food). If so, invoke it.
        public void ReflectiveVisit(IElement element)
        {
            var types = new Type[] { element.GetType() };
            var mi = this.GetType().GetMethod("Visit", types);

            if (mi != null)
            {
                mi.Invoke(this, new object[] { element });
            }
        }
    }

    /// <summary>
    /// A 'ConcreteVisitor' class
    /// </summary>
    class PriceVisitor : Visitor
    {
        // Visit clerk
        public void Visit(Pizza clerk)
        {
            DoVisit(clerk);
        }

        // Visit director
        public void Visit(Pasta director)
        {
            DoVisit(director);
        }

        private void DoVisit(IElement element)
        {
            var food = element as Food;

            // Provide 10% price raise
            food.Price *= 1.10;
            Console.WriteLine("{0} {1}'s new price: {2:C}",
                food.GetType().Name, food.Name,
                food.Price);
        }
    }

    /// <summary>
    /// A 'ConcreteVisitor' class
    /// </summary>
    class QuantityVisitor : Visitor
    {
        // Visit director
        public void Visit(Pasta director)
        {
            DoVisit(director);
        }

        private void DoVisit(IElement element)
        {
            var food = element as Food;

            // Provide 3 extra quantity
            food.Quantity += 3;
            Console.WriteLine("{0} {1}'s new quantity: {2}",
                food.GetType().Name, food.Name,
                food.Quantity);
        }
    }

    /// <summary>
    /// The 'Element' interface
    /// </summary>
    public interface IElement
    {
        void Accept(Visitor visitor);
    }

    /// <summary>
    /// The 'ConcreteElement' class
    /// </summary>
    class Food : IElement
    {
        // Constructor
        public Food(string name, double price,
            int quantity)
        {
            this.Name = name;
            this.Price = price;
            this.Quantity = quantity;
        }

        // Gets or sets name
        public string Name { get; set; }

        // Gets or set price
        public double Price { get; set; }

        // Gets or sets Quantity days
        public int Quantity { get; set; }

        public virtual void Accept(Visitor visitor)
        {
            visitor.ReflectiveVisit(this);
        }
    }

    /// <summary>
    /// The 'ObjectStructure' class
    /// </summary>
    class FastFood : List<Food>
    {
        public void Attach(Food food)
        {
            Add(food);
        }

        public void Detach(Food food)
        {
            Remove(food);
        }

        public void Accept(Visitor food)
        {
            // Iterate over all fastfood and accept visitor
            this.ForEach(item => item.Accept(food));

            Console.WriteLine();
        }
    }

    // Three Food types

    class Pizza : Food
    {
        // Constructor
        public Pizza()
            : base("Veggie Pizza", 100.0, 10)
        {
        }
    }

    class Pasta : Food
    {
        // Constructor
        public Pasta()
            : base("Corn Pasta", 50.0, 5)
        {
        }
    }

    class Burger : Food
    {
        // Constructor
        public Burger()
            : base("Veg Burger", 20.0, 25)
        {
        }
    }
}

Output:

0 comments :

Post a Comment

  • Popular Posts
  • Comments