views:

129

answers:

6

Consider this example

The Interface

interface IBusinessRules
{
    string Perform();
}

The Inheritors

class Client1BusinessRules: IBusinessRules
{
    public string Perform()
    {
        return "Business rule for Client 1 Performed";
    }
}

class Client2BusinessRules: IBusinessRules
{
    public string Perform()
    {
        return "Business rule for Client 2 Performed";
    }
}

class Client3BusinessRules: IBusinessRules
{
    public string Perform()
    {
        return "Business rule for Client 3 Performed";
    }
}

The factory class

class BusinessRulesFactory
{
    public IBusinessRules GetObject(int clientIdentityCode)
    {
        IBusinessRules objbase = null;
        switch (clientIdentityCode)
        {
            case 1:
                objbase = new Client1BusinessRules();
                break;
            case 2:
                objbase = new Client2BusinessRules();
                break;
            case 3:
                objbase = new Client3BusinessRules();
                break;
            default:
                throw new Exception("Unknown Object");
        }
        return objbase;
    }
}

sample usage:

class Program
{
    static void Main(string[] args)
    {
        BusinessRulesFactory objfactory = new BusinessRulesFactory ();
        IBusinessRulesFactory objBase = objfactory.GetObject(2);
        Console.WriteLine(objBase.Perform());

        objBase = objfactory.GetObject(3);
        Console.WriteLine(objBase.Perform());
        Console.Read();
    }
}

My question is, how about I add another method on the ALgorithm1 Class but not in the interface because im going to just use it on special scenario?

class Client1BusinessRules: IBusinessRules
{
    public string Perform()
    {
        return "Client1 Business rules is Performed";
    }


    public string Calculate()
    {
        return "Additional functionality for CLient1";
    }
}

how Am I suppose to call that on the UI something like this

 objBase = objfactory.GetObject(1);
 Console.WriteLine(objBase.Calculate());

Is there any other solution? thanks in advance

EDIT: I rewrite it to resemble my current project design

+3  A: 

The whole point of the factory pattern is to return the proper implementation of a contract so that the consumer shouldn't worry about how to instantiate it but simply invoke its methods. You could always test the actual type, cast to it and invoke the method but that's a very bad design and I wouldn't recommend it. The consumer shouldn't know anything about the actual type. You will need to rethink your design.

Darin Dimitrov
+2  A: 

There are many approaches that can be employed in this case, and it depends on the cost you're willing to put in order to get the value.

For example, you can go with simple casting. You'll get the algorithm object from the factory, cast it to the proper (specific) algorithm object, and then call the "Calculate" function.

Another option - a much more generic one, that would also require much more code - would be to supply a querying mechanism within the base class, that will supply information about the available functionality within the object. This is somewhat comparable to querying for interfaces in COM.

The important questions you need to ask yourself is: 1. How many times will you need to implement specific functionality? 2. Is there a way you can solve the problem with added polymorphism stemming from the base class? 3. Will users of the derived objects know that they are using the specific object, or do you want them to be ignorant of the actual type?

In general what I personally do in such cases is start with the simplest solution (in this case, specific casting and calling the function), and go back and refactor as I go, when I have some more data about the domain. If you're sensitive to "smelly code", you'll get to a point where you see there's too much clutter and you'll refactor it into a better solution.

Eldad Mor
im stuck on this problem for a month now, I tried different approach but all leads to dead end, Im refactoring my three tier project now because it's not so SCALABLE, I have a system/website that many clients (its represented by the Algorithm on my example) and the clients implement different set of business rules.. the problem here is that all the Client should use 1 Website, so what happens is that my code is so MESSED UP, lots of "if client1 then do this else if client2 then do this" you know what i mean
CSharpNoob
Well in that case, the best thing to do is to re-evaluate your entire design and start refactoring in a higher level. If you're not adequately experienced in that, I'd suggest consulting with someone who can teach you a couple of things about refactoring and help you complete this process (it's an ongoing, step-by-step process).
Eldad Mor
+2  A: 

I presume you are using the factory class in order to:

  • have a standard facade accepting parameters that lead to business rule selection and provisioning
  • encapsulate business rule provisioning
  • decouple the users from actual implementations of IBusinessRules

Hence I would solve your problem by introducing new interface

interface IComputableRules : IBusinessRules
{
    string Calculate();
}

As long as you follow the interface-based design, there's nothing wrong about casting the actual instance to an interface different from IBusinessRules.

IBusinessRules businessRule = objFactory.GetObject(...some input...)
...
// check if the computable service is supported and print the result
IComputableRules computable = businessRule as IComputableRules;
if (computable)
{
     Console.WriteLine(computable.Calculate());
}

Here you can think of you business rule classes as service providers, that guarantee some basic service, plus optional additional services depending on the nature of the business rule.

Note: By turning the BusinessRulesFactory into a generic class you might make the indication of a specific service a part of the factory contract, and make sure the returned business rule implementation will support a particular (otherwise optional) service.

class BusinessRulesFactory<TService> where TService : IBusinessRules
{
     public TService GetObject(int clientIdentityCode)
     {
         // ... choose business rule in respect to both clientIdentityCode and TService
     }
}

In case where you wouldn't require a specific additional service to be available, you'd just use IBusinessRules as the actual type parameter.

Ondrej Tucny
looks like creating another interface for Calculate() is the path to go.. thanks
CSharpNoob
One more note to “…but not in the interface because im going to just use it on special scenario?” — generally, it's a good idea to think whether it's possible treating special cases not as special cases, but in-line with the architecture of the remaining code. Special cases tend to become standard cases very quickly, so it's worth thinking twice about the architecture first, because it's cheaper.
Ondrej Tucny
A: 

This is a domain modelling issue and relates to what you mean by BusinessRule and IBase in your problem domain.

What is IBase? Sounds like it should be called IBusinessRule. In which case, what does Calculate mean in the context of a "business rule". If it has a generic meaning in your domain then IBusinessRule should implement it, as should the other classes, even if only as an empty method.

If it doesn't have generic meaning in your domain then your class should implement another interface ICalculable (IAlgorithm?) that has Calculate, which you call as:

ICalculable calculable = obj as ICalculable;
if ( calculable != null ) calculable.Calculate();
mancaus
sorry Typo yup its IBusinessRule
CSharpNoob
+2  A: 

If you want to stick to the current architecture you can introduce a new interface declaration

interface ICalculationRules  
{  
    string Calculate();  
}

Now let modify Client1BusinessRules by adding the interface declaration:

class Client1BusinessRules: IBusinessRules, ICalculationRules
{
     // everything remains the same  
}

Modify your calling code like this:

var objBase = objfactory.GetObject(1);  
Console.WriteLine(objBase.Calculate());    
var calcBase = obj as ICalculationRules;     
if (calcBase != null) calculable.Calculate();     

Maintenance implication: Every time you introduce a new interface, you have to touch all your calling code. Since you posted that this code is placed in the UI code, this can get quite a mess.

Each interface you are introducing just means added behaviour to a class. If you have a large range of different behaviours, then the solution above my not feel right, because there is always the need to use the as operation and conditional execution a method. If you want to stick to some classic design pattern this variability of behaviour can be countered with the Decorator Pattern or the Strategy Pattern. They can be smoothly combined with the Factory Pattern.

Theo Lenndorff
+1  A: 

I would modify it like this

interface IBusinessRules
{
    string Perform();
    bool CanCalculate { get; }
    string Calculate();
}

and add an abstract base class (optional but recommended for further extensibility)

public abstract class BusinessRules : IBusinessRules {
    protected BusinessRules() { 
    }

    protected virtual bool CanCalculateCore() {
         return false; // Cannot calculate by default
    }

    protected virtual string CalculateCore() { 
         throw new NotImplementedException("Cannot calculate"); 
    }

    protected abstract string PerformCore();

    #region IBusinessRules Members

    public string Perform()
    {
        return PerformCore();
    }

    public bool CanCalculate
    {
        get { return CanCalculateCore(); }
    }

    public string Calculate()
    {
        return CalculateCore();
    }

    #endregion
}

So the call site now looks neat:

objBase = objfactory.GetObject(1);
if (objBase.CanCalculate) {
    Console.WriteLine(objBase.Calculate());
}

One big problem of extending the interface is, it gives the caller no hint at all that you might support that interface as well.

tia