0

I'm currently have an implementation of Chain of Responsibility which return objects that implement IResponse.

public interface IRequest
{
}

public interface IResponse
{
}

public interface IFactory
{
    bool CanHandle(IRequest request);
    IResponse HandleRequest(IRequest request);
}

public class Foo : IResponse
{
    public void SpecificMethod()
    {
        Console.WriteLine("SpecificMethod() only belongs to Foo");
    }
}

public class FooRequest : IRequest
{
}

public class FooFactory : IFactory
{
    public bool CanHandle(IRequest request)
    {
        return request is FooRequest;
    }

    public IResponse HandleRequest(IRequest request)
    {
        return new Foo();
    }
}

public class FactoryManager
{
    private readonly List<IFactory> _factoryImplementations = new List<IFactory>();

    public void Register(IFactory factory)
    {
        _factoryImplementations.Add(factory);
    }

    public IResponse HandleRequest(IRequest request)
    {
        foreach (var factory in _factoryImplementations)
        {
            if (factory.CanHandle(request))
            {
                return factory.HandleRequest(request);
            }
        }
        return null;
    }
}



class Program
{
    static void Main()
    {
        var manager = new FactoryManager();
        manager.Register(new FooFactory());
        var foo = (Foo) manager.HandleRequest(new FooRequest()); // How can I remove this cast?
        foo.SpecificMethod();
        Console.ReadLine();
    }
}

The purpose of this implementation is to make it easy to replace implementations whenever I need. The problem is that I have to explicitly cast the type which I made the request for if I want to do anything specific with the object, like accessing foo.SpecificMethod().

Is there any way to have this (Foo) cast gone?

Edit: It's possible to solve this issue with a dynamic variable, but a statically typed way of solving it would be preferrable.

thalesmello
  • 3,301
  • 3
  • 20
  • 20
  • Add the method to `IResponse` interface? or use more error prone `dynamic` typing? – Sriram Sakthivel Oct 16 '14 at 18:09
  • I don't like wither. I can't include it in `IResponse` because I don't want other implementations of IResponse to deal with that. I don't think dynamic is a good solution either, because I'm looking for a statically typed way of doing this. – thalesmello Oct 16 '14 at 18:35
  • Unfortunately there is no way to avoid the cast. You can push the responsibility of cast to another object but the fact is you can't. If you want to downcast, you have a leaky abstraction. – Sriram Sakthivel Oct 16 '14 at 18:41
  • How about IFactory where T:IRequest whence FooFactory can return a Foo + IRequest whence FooRequest knows it wants to return a foo and an overload on manager public IResponse HandleRequest(IRequest request) ? – tolanj Oct 16 '14 at 19:18
  • tolanj, could you elaborate more, please? What kind of role would `IResponse` play here? If you can write an example, it would be clearer to understand – thalesmello Oct 16 '14 at 20:33
  • 1
    The generics option may look like [this fiddle](https://dotnetfiddle.net/PCKQsW) – Daniel J.G. Oct 16 '14 at 20:35

1 Answers1

0

If you want to be able to call a unique function that isn't on the main interface, you will have to cast it (or request a more specific interface with that method on it).

Using an interface means "This method will have these available public methods". You can inherit from multiple interfaces (public interface IMoreSpeific : IGeneric) but you can't make calls to specific class implementations that have other methods without casting it.

You can make something generic like a DoWork() method on your interface, but the purpose of the interface is to have something reusable and generic.

John
  • 6,503
  • 3
  • 37
  • 58