Strategy Pattern problem (or casting problem)

P

philippe sillon

Hi,

I have a problem to implemente the strategy pattern. the problem come
from that a method take different arguments type (object in interface
and String / Int in implemented class).

When price3 instance call getPrice, the method invoked is the one of
PriceRule abstract class. But, I want to invoke the method of
PriceruleForRegion. So I think the solution is somewhere on casting to
original type (PriceRuleForRegion) but I don't how I can do that ?

Thank you for your help.


Example of code is here :

using System;

namespace ProblemCast_phil
{

class Class1
{

[STAThread]
static void Main(string[] args)
{
// THIS IS WORKING FINE
PriceRuleForRegion price1 = new PriceRuleForRegion ("QC", 100);
PriceRuleForQuantity price2 = new PriceRuleForQuantity (1, 200);

Console.WriteLine ("GetPrice based on Quebec :
{0:c}",price1.getPrice ("QC"));
Console.WriteLine ("GetPrice based on Quebec :
{0:c}",price1.getPrice ("ON"));

Console.WriteLine ("GetPrice based on quantity ordered (1) :
{0:c}",price2.getPrice (1));
Console.WriteLine ("GetPrice based on quantity ordered (2) :
{0:c}",price2.getPrice (2));



// THIS BLOCK FAILED.
PriceRule price3 = new PriceRuleForRegion ("QC", 100);
PriceRule price4 = new PriceRuleForQuantity (1, 200);


// EXCEPTION : The following line generate exception - See line 58
Console.WriteLine ("GetPrice based on Quebec :
{0:c}",price3.getPrice ("QC"));
Console.WriteLine ("GetPrice based on Quebec :
{0:c}",price3.getPrice ("ON"));

Console.WriteLine ("GetPrice based on quantity ordered (1) :
{0:c}",price4.getPrice (1));
Console.WriteLine ("GetPrice based on quantity ordered (2) :
{0:c}",price4.getPrice (2));




Console.ReadLine ();

}
}


// ABSTRACT RULE CLASS
abstract class PriceRule
{
protected float m_price;


public PriceRule (float price)
{
this.m_price = price;
}

public float getPrice (object obj)
{
throw new ApplicationException ("The program is not supose to call
this method.");
}

}

// FIRST IMPLEMENTATION FOR RULE
class PriceRuleForRegion : PriceRule
{
private string m_region;

public PriceRuleForRegion (string region, float price)
:base (price)
{
this.m_region = region;
}

public float getPrice (string region)
{
if (this.m_region == region) return m_price;

return -1;
}

}

// FIRST IMPLEMENTATION FOR RULE
class PriceRuleForQuantity : PriceRule
{
private int m_quantity;

public PriceRuleForQuantity (int quantity, float price)
:base (price)
{
this.m_quantity = quantity;
}

public float getPrice (int quantity)
{
if (this.m_quantity == quantity) return this.m_price;

return -1;
}

}



}


Philippe SILLON
 
F

Frans Bouma [C# MVP]

philippe said:
I have a problem to implemente the strategy pattern. the problem come
from that a method take different arguments type (object in interface
and String / Int in implemented class).

When price3 instance call getPrice, the method invoked is the one of
PriceRule abstract class. But, I want to invoke the method of
PriceruleForRegion. So I think the solution is somewhere on casting to
original type (PriceRuleForRegion) but I don't how I can do that ?

You should make GetPrice virtual in teh base class and override the method
in the derived classes.

The strategy pattern works like this:

public class Foo
{
// .. init code, constructors etc.

public virtual void Strategic()
{
}

public void MyCoolMethod()
{
// some code

Strategic();

// other code
}
}

public class Bar:Foo
{
public override void Strategic()
{
// strategic method implementation
}
}


now when you do this:
Bar b = new Bar();
b.MyCoolMethod();

b's implementation will be called, but..

Foo f = new Bar();
f.MyCoolMethod();

also will call b's implementation.

However your code doesn't show a schema like this where you 'inject' code via
polymorphism into a base class' implementation, as you don't override a base
class method which is called by the base class logic.

Frans.

Thank you for your help.


Example of code is here :

using System;

namespace ProblemCast_phil
{

class Class1
{

[STAThread]
static void Main(string[] args)
{
// THIS IS WORKING FINE
PriceRuleForRegion price1 = new PriceRuleForRegion ("QC", 100);
PriceRuleForQuantity price2 = new PriceRuleForQuantity (1, 200);

Console.WriteLine ("GetPrice based on Quebec :
{0:c}",price1.getPrice ("QC"));
Console.WriteLine ("GetPrice based on Quebec :
{0:c}",price1.getPrice ("ON"));

Console.WriteLine ("GetPrice based on quantity ordered (1) :
{0:c}",price2.getPrice (1));
Console.WriteLine ("GetPrice based on quantity ordered (2) :
{0:c}",price2.getPrice (2));



// THIS BLOCK FAILED.
PriceRule price3 = new PriceRuleForRegion ("QC", 100);
PriceRule price4 = new PriceRuleForQuantity (1, 200);


// EXCEPTION : The following line generate exception - See line 58
Console.WriteLine ("GetPrice based on Quebec :
{0:c}",price3.getPrice ("QC"));
Console.WriteLine ("GetPrice based on Quebec :
{0:c}",price3.getPrice ("ON"));

Console.WriteLine ("GetPrice based on quantity ordered (1) :
{0:c}",price4.getPrice (1));
Console.WriteLine ("GetPrice based on quantity ordered (2) :
{0:c}",price4.getPrice (2));




Console.ReadLine ();

}
}


// ABSTRACT RULE CLASS
abstract class PriceRule
{
protected float m_price;


public PriceRule (float price)
{
this.m_price = price;
}

public float getPrice (object obj)
{
throw new ApplicationException ("The program is not supose to call
this method.");
}

}

// FIRST IMPLEMENTATION FOR RULE
class PriceRuleForRegion : PriceRule
{
private string m_region;

public PriceRuleForRegion (string region, float price)
:base (price)
{
this.m_region = region;
}

public float getPrice (string region)
{
if (this.m_region == region) return m_price;

return -1;
}

}

// FIRST IMPLEMENTATION FOR RULE
class PriceRuleForQuantity : PriceRule
{
private int m_quantity;

public PriceRuleForQuantity (int quantity, float price)
:base (price)
{
this.m_quantity = quantity;
}

public float getPrice (int quantity)
{
if (this.m_quantity == quantity) return this.m_price;

return -1;
}

}



}


Philippe SILLON
 
P

philippe sillon

Hi,

Ok, but what append if I want to add new function but with different
signature (like add one parameter string).
I don't want to cast foo variable (type Foo) to type Bar because I can
have different implementation of Foo class.
It's like I need to cast but the cast depend on instance type (foo
variable is a Bar type but the reference is a Foo type)

Thank you for your help.


He is an example :

using System;

namespace ProblemCast_phil
{
public class Class2
{
static void Main (string[] args)
{

// EVERYTHING IS PERFECT EXCEPT THE LAST LINE
Bar bar = new Bar ();
bar.Strategic ();

Foo foo = new Bar ();
foo.Strategic ();
foo.MyCoolMethod ();

// THIS LINE. I GOT THE FOLLWING ERROR AT COMPILATION :
// Class2.cs(22): No overload for method 'Strategic' takes '1'
arguments
foo.Strategic ("From Philippe");

Console.ReadLine ();
}
}

public class Foo
{
// .. init code, constructors etc.

public virtual void Strategic()
{
Console.WriteLine ("Call Foo.Strategic");
}

public void MyCoolMethod()
{
// some code
Console.WriteLine ("Call Foo.MyCollMethod");

Strategic();

// other code
}
}

public class Bar:Foo
{
public override void Strategic()
{
// strategic method implementation
Console.WriteLine ("Call Bar.Strategic");
}

public void Strategic (string message)
{
// strategic method implementation
Console.WriteLine ( "Call Bar.Strategic with message" + message );
}

}


}
 
Top