Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Implementing Strategy Pattern

Implementing Strategy Pattern

Scheduled Pinned Locked Moved C#
regexhelp
10 Posts 5 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    Liagapi
    wrote on last edited by
    #1

    I'm trying to calculate the area of different shapes using Strategy pattern and below are my code thus far.

    public class Shape
    { public string Name{get;set;}
    }
    public class Circle:Shape
    { public double Radius{get;set;}
    public Circle (string name, double radius)
    {Name = name; Radius = radius;}
    }
    public class Square:Shape
    { public double Side {get; set;}
    public Square(string name, double side)
    { Name = name; Side = side;}
    }
    public interface ICalculateAreaStrategy
    { double Calculate(Shape shape);
    }
    public class CalculateCircleAreaStrategy: ICalculateAreaStrategy
    { double Calculate(Shape shape)
    {
    return Math.Pow(shape.Radius,2)*3.14;
    }
    }
    public class CalculateSquareAreaStrategy: ICalculateAreaStrategy
    { double Calculate(Shape shape)
    {
    return shape.Side * shape.Side
    }
    }
    public class CalculateAreaService
    { readonly ICalculateAreaStrategy calculateAreaStrategy;
    public CalculateAreaService(ICalculateAreaStrategy strategy)
    {
    calculateAreaStrategy = strategy;
    }
    double CalculateArea(Shape shape)
    {
    return calculateAreaStrategy.Calculate(shape);
    }
    }

    The reason I'm stuck is I cannot get access to the Circle or Square class from the Shape object passed to the Calculate() method in the CalculateCircleAreaStrategy and CalculateSquareAreaStrategy classes.

    P L F 4 Replies Last reply
    0
    • L Liagapi

      I'm trying to calculate the area of different shapes using Strategy pattern and below are my code thus far.

      public class Shape
      { public string Name{get;set;}
      }
      public class Circle:Shape
      { public double Radius{get;set;}
      public Circle (string name, double radius)
      {Name = name; Radius = radius;}
      }
      public class Square:Shape
      { public double Side {get; set;}
      public Square(string name, double side)
      { Name = name; Side = side;}
      }
      public interface ICalculateAreaStrategy
      { double Calculate(Shape shape);
      }
      public class CalculateCircleAreaStrategy: ICalculateAreaStrategy
      { double Calculate(Shape shape)
      {
      return Math.Pow(shape.Radius,2)*3.14;
      }
      }
      public class CalculateSquareAreaStrategy: ICalculateAreaStrategy
      { double Calculate(Shape shape)
      {
      return shape.Side * shape.Side
      }
      }
      public class CalculateAreaService
      { readonly ICalculateAreaStrategy calculateAreaStrategy;
      public CalculateAreaService(ICalculateAreaStrategy strategy)
      {
      calculateAreaStrategy = strategy;
      }
      double CalculateArea(Shape shape)
      {
      return calculateAreaStrategy.Calculate(shape);
      }
      }

      The reason I'm stuck is I cannot get access to the Circle or Square class from the Shape object passed to the Calculate() method in the CalculateCircleAreaStrategy and CalculateSquareAreaStrategy classes.

      P Offline
      P Offline
      Pete OHanlon
      wrote on last edited by
      #2

      The reason you can't access it is because you are passing in a Shape which does not have the relevant parameters because they are defined in the subclasses. If you know that you are passing in a certain type, then you just need to cast them before you try to access them. For instance, in the Circle strategy, your Calculate method could be converted to this:

      double Calculate(Shape shape)
      {
      Circle circle = shape as Circle;
      if (circle == null)
      {
      throw new InvalidOperationException("You didn't pass in a circle");
      }
      return Math.Pow(circle.Radius, 2)* 3.14;
      }

      This space for rent

      L 1 Reply Last reply
      0
      • L Liagapi

        I'm trying to calculate the area of different shapes using Strategy pattern and below are my code thus far.

        public class Shape
        { public string Name{get;set;}
        }
        public class Circle:Shape
        { public double Radius{get;set;}
        public Circle (string name, double radius)
        {Name = name; Radius = radius;}
        }
        public class Square:Shape
        { public double Side {get; set;}
        public Square(string name, double side)
        { Name = name; Side = side;}
        }
        public interface ICalculateAreaStrategy
        { double Calculate(Shape shape);
        }
        public class CalculateCircleAreaStrategy: ICalculateAreaStrategy
        { double Calculate(Shape shape)
        {
        return Math.Pow(shape.Radius,2)*3.14;
        }
        }
        public class CalculateSquareAreaStrategy: ICalculateAreaStrategy
        { double Calculate(Shape shape)
        {
        return shape.Side * shape.Side
        }
        }
        public class CalculateAreaService
        { readonly ICalculateAreaStrategy calculateAreaStrategy;
        public CalculateAreaService(ICalculateAreaStrategy strategy)
        {
        calculateAreaStrategy = strategy;
        }
        double CalculateArea(Shape shape)
        {
        return calculateAreaStrategy.Calculate(shape);
        }
        }

        The reason I'm stuck is I cannot get access to the Circle or Square class from the Shape object passed to the Calculate() method in the CalculateCircleAreaStrategy and CalculateSquareAreaStrategy classes.

        L Offline
        L Offline
        Lost User
        wrote on last edited by
        #3

        This isn't what the strategy pattern is for anyway. You could just define these methods on their respective classes, it doesn't make sense to calculate the area of a circle *as if* it was a square, and vice versa. So changing the strategy doesn't even apply to this situation. Even if you *do* apply it, a strategy is supposed is not supposed to work only conditionally, they're supposed to be usable interchangeably - that's their whole point.

        L 1 Reply Last reply
        0
        • L Liagapi

          I'm trying to calculate the area of different shapes using Strategy pattern and below are my code thus far.

          public class Shape
          { public string Name{get;set;}
          }
          public class Circle:Shape
          { public double Radius{get;set;}
          public Circle (string name, double radius)
          {Name = name; Radius = radius;}
          }
          public class Square:Shape
          { public double Side {get; set;}
          public Square(string name, double side)
          { Name = name; Side = side;}
          }
          public interface ICalculateAreaStrategy
          { double Calculate(Shape shape);
          }
          public class CalculateCircleAreaStrategy: ICalculateAreaStrategy
          { double Calculate(Shape shape)
          {
          return Math.Pow(shape.Radius,2)*3.14;
          }
          }
          public class CalculateSquareAreaStrategy: ICalculateAreaStrategy
          { double Calculate(Shape shape)
          {
          return shape.Side * shape.Side
          }
          }
          public class CalculateAreaService
          { readonly ICalculateAreaStrategy calculateAreaStrategy;
          public CalculateAreaService(ICalculateAreaStrategy strategy)
          {
          calculateAreaStrategy = strategy;
          }
          double CalculateArea(Shape shape)
          {
          return calculateAreaStrategy.Calculate(shape);
          }
          }

          The reason I'm stuck is I cannot get access to the Circle or Square class from the Shape object passed to the Calculate() method in the CalculateCircleAreaStrategy and CalculateSquareAreaStrategy classes.

          F Offline
          F Offline
          F ES Sitecore
          wrote on last edited by
          #4

          To answer your specific question you need to up caste to the type you need

          public class Shape
          {
          public string Name { get; set; }
          }

          public class Circle : Shape
          {
          public double Radius { get; set; }
          public Circle(string name, double radius)
          { Name = name; Radius = radius; }
          }

          public class Square : Shape
          {
          public double Side { get; set; }
          public Square(string name, double side)
          { Name = name; Side = side; }
          }

          public interface ICalculateAreaStrategy
          {
          double Calculate(Shape shape);
          }

          public class CalculateCircleAreaStrategy : ICalculateAreaStrategy
          {
          public double Calculate(Shape shape)
          {
          // "up cast" the Shape to a Circle, if shape is not a Circle then "as" will return null
          Circle c = shape as Circle;

              if (c == null)
              {
                  return 0;
              }
          
              return 3.14 \* c.Radius \* c.Radius;
          }
          

          }

          public class CalculateSquareAreaStrategy : ICalculateAreaStrategy
          {
          public double Calculate(Shape shape)
          {
          // "up cast" the Shape to a Square, if shape is not a Square then "as" will return null
          Square s = shape as Square;

              if (s == null)
              {
                  return 0;
              }
          
              return s.Side \* s.Side;
          }
          

          }

          public class CalculateAreaService
          {
          readonly ICalculateAreaStrategy calculateAreaStrategy;

          public CalculateAreaService(ICalculateAreaStrategy strategy)
          {
              calculateAreaStrategy = strategy;
          }
          
          public double CalculateArea(Shape shape)
          {
              return calculateAreaStrategy.Calculate(shape);
          }
          

          }

          Usage

          CalculateAreaService cas = new CalculateAreaService(new CalculateSquareAreaStrategy());

          Console.WriteLine(cas.CalculateArea(new Square("Square", 3)));

          cas = new CalculateAreaService(new CalculateCircleAreaStrategy());

          Console.WriteLine(cas.CalculateArea(new Circle("Circle", 3)));

          Console.ReadLine();

          However the strategy pattern isn't that great for things that require different parameters such as you have with Square, Circle etc. I appreciate you're doing this to learn the strategy pattern and this might not be your ultimate use for it, but if you wanted to do something like you're doing then you could do it more simply like this

          public interface ICalculateArea
          {
          double Calculate();
          }

          public class CalculateCircleArea : ICalculateArea
          {
          private Circle circle;

          public CalculateCircleArea(Circle circle)
          {
              this.cir
          
          L 1 Reply Last reply
          0
          • P Pete OHanlon

            The reason you can't access it is because you are passing in a Shape which does not have the relevant parameters because they are defined in the subclasses. If you know that you are passing in a certain type, then you just need to cast them before you try to access them. For instance, in the Circle strategy, your Calculate method could be converted to this:

            double Calculate(Shape shape)
            {
            Circle circle = shape as Circle;
            if (circle == null)
            {
            throw new InvalidOperationException("You didn't pass in a circle");
            }
            return Math.Pow(circle.Radius, 2)* 3.14;
            }

            This space for rent

            L Offline
            L Offline
            Liagapi
            wrote on last edited by
            #5

            Thanks, that's exactly what I needed.

            1 Reply Last reply
            0
            • F F ES Sitecore

              To answer your specific question you need to up caste to the type you need

              public class Shape
              {
              public string Name { get; set; }
              }

              public class Circle : Shape
              {
              public double Radius { get; set; }
              public Circle(string name, double radius)
              { Name = name; Radius = radius; }
              }

              public class Square : Shape
              {
              public double Side { get; set; }
              public Square(string name, double side)
              { Name = name; Side = side; }
              }

              public interface ICalculateAreaStrategy
              {
              double Calculate(Shape shape);
              }

              public class CalculateCircleAreaStrategy : ICalculateAreaStrategy
              {
              public double Calculate(Shape shape)
              {
              // "up cast" the Shape to a Circle, if shape is not a Circle then "as" will return null
              Circle c = shape as Circle;

                  if (c == null)
                  {
                      return 0;
                  }
              
                  return 3.14 \* c.Radius \* c.Radius;
              }
              

              }

              public class CalculateSquareAreaStrategy : ICalculateAreaStrategy
              {
              public double Calculate(Shape shape)
              {
              // "up cast" the Shape to a Square, if shape is not a Square then "as" will return null
              Square s = shape as Square;

                  if (s == null)
                  {
                      return 0;
                  }
              
                  return s.Side \* s.Side;
              }
              

              }

              public class CalculateAreaService
              {
              readonly ICalculateAreaStrategy calculateAreaStrategy;

              public CalculateAreaService(ICalculateAreaStrategy strategy)
              {
                  calculateAreaStrategy = strategy;
              }
              
              public double CalculateArea(Shape shape)
              {
                  return calculateAreaStrategy.Calculate(shape);
              }
              

              }

              Usage

              CalculateAreaService cas = new CalculateAreaService(new CalculateSquareAreaStrategy());

              Console.WriteLine(cas.CalculateArea(new Square("Square", 3)));

              cas = new CalculateAreaService(new CalculateCircleAreaStrategy());

              Console.WriteLine(cas.CalculateArea(new Circle("Circle", 3)));

              Console.ReadLine();

              However the strategy pattern isn't that great for things that require different parameters such as you have with Square, Circle etc. I appreciate you're doing this to learn the strategy pattern and this might not be your ultimate use for it, but if you wanted to do something like you're doing then you could do it more simply like this

              public interface ICalculateArea
              {
              double Calculate();
              }

              public class CalculateCircleArea : ICalculateArea
              {
              private Circle circle;

              public CalculateCircleArea(Circle circle)
              {
                  this.cir
              
              L Offline
              L Offline
              Liagapi
              wrote on last edited by
              #6

              Thank you for your time, I would not have known that the Strategy pattern isn't suited for my situation if you hadn't shared your thoughts. Can you please explain why "the strategy pattern isn't that great for things that require different parameters". I've checked the definition of the Strategy pattern and there wasn't anything that says it shouldn't be used on situations that are similar to mine. The following are part of the definition of the Strategy pattern I've found online.

              * “Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.” (Gang of Four)

              * "Specifies a set of classes, each representing a potential behaviour. Switching between those classes changes the application behaviour. (The Strategy)

              From my perspective all of my classes which inherit from the ICalculateAreaStrategy interface have the same exact method and it takes the same exact number and type of parameter no matter which class it's used in.

              B 1 Reply Last reply
              0
              • L Lost User

                This isn't what the strategy pattern is for anyway. You could just define these methods on their respective classes, it doesn't make sense to calculate the area of a circle *as if* it was a square, and vice versa. So changing the strategy doesn't even apply to this situation. Even if you *do* apply it, a strategy is supposed is not supposed to work only conditionally, they're supposed to be usable interchangeably - that's their whole point.

                L Offline
                L Offline
                Liagapi
                wrote on last edited by
                #7

                Thanks for replying. I'll look into this topic more.

                1 Reply Last reply
                0
                • L Liagapi

                  I'm trying to calculate the area of different shapes using Strategy pattern and below are my code thus far.

                  public class Shape
                  { public string Name{get;set;}
                  }
                  public class Circle:Shape
                  { public double Radius{get;set;}
                  public Circle (string name, double radius)
                  {Name = name; Radius = radius;}
                  }
                  public class Square:Shape
                  { public double Side {get; set;}
                  public Square(string name, double side)
                  { Name = name; Side = side;}
                  }
                  public interface ICalculateAreaStrategy
                  { double Calculate(Shape shape);
                  }
                  public class CalculateCircleAreaStrategy: ICalculateAreaStrategy
                  { double Calculate(Shape shape)
                  {
                  return Math.Pow(shape.Radius,2)*3.14;
                  }
                  }
                  public class CalculateSquareAreaStrategy: ICalculateAreaStrategy
                  { double Calculate(Shape shape)
                  {
                  return shape.Side * shape.Side
                  }
                  }
                  public class CalculateAreaService
                  { readonly ICalculateAreaStrategy calculateAreaStrategy;
                  public CalculateAreaService(ICalculateAreaStrategy strategy)
                  {
                  calculateAreaStrategy = strategy;
                  }
                  double CalculateArea(Shape shape)
                  {
                  return calculateAreaStrategy.Calculate(shape);
                  }
                  }

                  The reason I'm stuck is I cannot get access to the Circle or Square class from the Shape object passed to the Calculate() method in the CalculateCircleAreaStrategy and CalculateSquareAreaStrategy classes.

                  L Offline
                  L Offline
                  Lost User
                  wrote on last edited by
                  #8

                  My first impulse would have been to use polymorphism: [Polymorphism (C# Programming Guide)](https://msdn.microsoft.com/en-us/library/ms173152.aspx) (The example looks very familiar).

                  "(I) am amazed to see myself here rather than there ... now rather than then". ― Blaise Pascal

                  1 Reply Last reply
                  0
                  • L Liagapi

                    Thank you for your time, I would not have known that the Strategy pattern isn't suited for my situation if you hadn't shared your thoughts. Can you please explain why "the strategy pattern isn't that great for things that require different parameters". I've checked the definition of the Strategy pattern and there wasn't anything that says it shouldn't be used on situations that are similar to mine. The following are part of the definition of the Strategy pattern I've found online.

                    * “Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.” (Gang of Four)

                    * "Specifies a set of classes, each representing a potential behaviour. Switching between those classes changes the application behaviour. (The Strategy)

                    From my perspective all of my classes which inherit from the ICalculateAreaStrategy interface have the same exact method and it takes the same exact number and type of parameter no matter which class it's used in.

                    B Offline
                    B Offline
                    Bernhard Hiller
                    wrote on last edited by
                    #9

                    Liagapi wrote:

                    vary independently from clients

                    That's the point: in your case, a Circle requires the algorithm for a circle, not for a rectangle, etc.: the algorithm absolutely depends on the client. Think of something different, say a chess game. How to find out the next move? You could use "brute force" calculating a few moves ahead, or you could implement some "artificial intelligence strategy". There could be external constraints, e.g. how much time you may use for calculating the next move, and hence apply different algorithms with different trade-offs. Select the algorithm applicable for the current scenario - and with the next scenario use an algorithm for that scenario.

                    L 1 Reply Last reply
                    0
                    • B Bernhard Hiller

                      Liagapi wrote:

                      vary independently from clients

                      That's the point: in your case, a Circle requires the algorithm for a circle, not for a rectangle, etc.: the algorithm absolutely depends on the client. Think of something different, say a chess game. How to find out the next move? You could use "brute force" calculating a few moves ahead, or you could implement some "artificial intelligence strategy". There could be external constraints, e.g. how much time you may use for calculating the next move, and hence apply different algorithms with different trade-offs. Select the algorithm applicable for the current scenario - and with the next scenario use an algorithm for that scenario.

                      L Offline
                      L Offline
                      Liagapi
                      wrote on last edited by
                      #10

                      Hi, thank you so much for your input. I am trying to learn this design pattern the right way the first time around so please bear with me. I'm still not clear how my implementation of the Strategy pattern is different from the one shown in the following link. design-patterns-and-practices-in-net-the-strategy-pattern/

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups