dmigo
dmigo

Reputation: 3029

How should I choose an instance of an AbstractFactory?

Currently I'm having a trouble with instantiating an AbstractFactory. There are some classes:

abstract class ABase { }
class A1 : ABase { }
class A2 : ABase { }

abstract class BBase { }
class B1 : BBase
{
    private readonly A1 _a;
    public B1(A1 a)
    {
        _a = a;
    }
}
class B2 : BBase
{
    private readonly A2 _a;
    public B2(A2 a)
    {
        _a = a;
    }
}


abstract class FactoryBBase
{
    abstract public BBase Create(ABase b);
}
class FactoryB1 : FactoryBBase
{
    override public BBase Create(ABase b)
    {
        return new B1(b as A1);
    }
}
class FactoryB2 : FactoryBBase
{
    override public BBase Create(ABase b)
    {
        return new B2(b as A2);
    }
}

class Runtime
{
    public void ProcessA(ABase a)
    {
        //How should I choose a proper factory?
    }
}

How do I instantiate a proper abstract factory in ProcessA method depending on the type of a? The thing is that I don't want to have a big if/else block.

Upvotes: 2

Views: 111

Answers (3)

bstenzel
bstenzel

Reputation: 1241

How to implement abstract factory really depends on what you need. What you have there is indeed a proper implementation, but I think it's not exactly what you need since you want to do something differently dependending on the type or state of an instance of ABase.

The logic that analyses the type or state is exactly what I'd put into a factory.

abstract class ABase { }
class A1 : ABase { }
class A2 : ABase { }

public abstract class FactoryBBase
{
    public abstract IProcessor Create(ABase a);
}
public class ConcreteFactory : FactoryBBase
{
    override public IProcessor Create(ABase a)
    {
        // this is ugly for a large amount of ABase implementations of course
        if (a is A1)
        {
            return new Runtime1();
        }
        if (a is A2)
        {
            return new Runtime2();
        }
        throw new NotSupportedException();
    }
}

public interface IProcessor
{
    void ProcessA(ABase a);
}

public class Runtime1 : IProcessor
{
    public void ProcessA(ABase a)
    {
        // process away
    }
}

public class Runtime2 : IProcessor
{
    public void ProcessA(ABase a)
    {
        // process away differently
    }
}

Multiple factory implementations come into play when you want the same type of ABase implementation to be processed by different types of Runtime/Processor depending on state that is outside of ABase.

Upvotes: 1

Greg
Greg

Reputation: 1116

You can use a lookup dictionary instead of a if-else/switch construct.

//classes used as markers
public interface IMarker {}
public class MarkerA : IMarker {}
public class MarkerB : IMarker {}

//classes to be created
public interface IData {}
public class DataA : IData {}
public class DataB : IData {}

//factory to call abstract factories (could use static here)
public class Factory
{
    public IData Create(IMarker marker)
    {
        //lookup dictionary instead of if/switch
        //func ensures instance is only created when required
        var lookup = new Dictionary<Type, Func<DataFactoryBase>>()
        {
            { typeof(MarkerA), () => new DataAFactory() },
            { typeof(MarkerB), () => new DataBFactory() },
        };

        //get factory by type and call constructor
        return lookup[marker.GetType()]().Create();
    }
}

//abstract factories
public abstract class DataFactoryBase
{
    public abstract IData Create();
}

public class DataAFactory : DataFactoryBase
{
    public override IData Create()
    {
        return new DataA();
    }
}

public class DataBFactory : DataFactoryBase
{
    public override IData Create()
    {
        return new DataB();
    }
}


public static void Main()
{
    //example will return DataA 
    IData data = new Factory().Create(new MarkerA());   
}

Upvotes: 1

Michal Krasny
Michal Krasny

Reputation: 5916

how to instantiate a proper abstract factory in ProcessA method depending on the type of a?

To avoid big if/else block you can put all factories into a map, where key is the type of a and value is the implementation. in Java I would do this either by Spring or I would create a static code, that can initialize the map when the class is loaded.

do I use AbstractFactory pattern as it is supposed to be uesd?

IMHO yes.

Upvotes: 1

Related Questions