工厂设计模式和依赖注入实现

时间:2014-05-19 04:45:04

标签: c# design-patterns dependency-injection abstract-factory

目前我正在尝试实现一些设计结构,工厂看起来最合适,就依赖注入而言,我更喜欢构造函数注入。然而,问题出现了并非所有我的产品都需要相同的依赖性,这种模式的混淆......

我的抽象工厂.get()方法必须如此

abstract class AbstractSpellFactory
{
    public abstract WCSpell get(SpellSubType sSubType,SpellCard,int a,int b,int c,int d);
}

为了完成起见,这里是我正在做/使用

的上下文中的法术等级
public abstract class WCSpell
{
    public abstract void CastSpell();
}

然后我可以像

一样使用它
AbstractSpellFactory aSpellFactory = SpellFactory.createSpellFactory(SpellType.buff);
WCSpell spell = aSpellFactory.get(SpellSubType.Positive,sCard,1,2,3,4);//OK
spell.CastSpell();

aSpellFactory = SpellFactory.createSpellFactory(SpellType.rotate);
spell = aSpellFactory.get(SpellSubType.clockwise,sCard,0,0,0,0);//Non-used/Needed values...
spell.CastSpell();

所以这是有效的,但首先是旋转法术不需要整数的事实有点不优雅,但最大的问题是如果我添加任何具有不同依赖性的新法术AbstractSpellFactory.get(...)方法参数参数只会变得更大,并且根据它可能甚至不需要传递值的拼写类型。

所以我有点卡住,有没有人有任何建议?

Psuedo实现上面的代码

拼写工厂类

static class SpellFactory
{
    public static AbstractSpellFactory createSpellFactory( SpellType sType )
    {
        AbstractSpellFactory sFactory = null;

        switch(sType)
        {
            case SpellType.kBuff:
            {
                sFactory = new SpellBuffFactory();
            }
                break;

            case SpellType.kRotateClockWise:
            {
                sFactory = new SpellRotateFactory();
            }
                break;
        }

        return sFactory;
    }
}

Buff Spell Factory

public class SpellBuffFactory : AbstractFactory
{
    public override Spell get( SpellSubType sSubType,SpellCard sCard,int a,int b,int c,int d)
    {
        Spell spell = null;

        switch(sSubType)
        {
            case Positive:
            {
                spell = new BuffSpell(a,b,c,d,sCard);
            }
                break;

            case Negative:
            {
                spell = new BuffSpell(-a,-b,-c,-d,sCard);//some check to make sure all values are negative
            }
        }

        return spell;
    }
}

旋转法术工厂

public class SpellRotateFactory : AbstractFactory
{
    public override Spell get( SpellSubType sSubType,SpellCard sCard,int a,int b,int c, int d)
    {
        Spell spell = null;

        switch(sSubType)
        {
            case Clockwise:
            {
                spell = new WCRotateSpell(WCRotateSpell.RotationDirection.Clockwise,sCard);
            }
                break;

            case CounterClockwise:
            {
                spell = new WCRotateSpell(WCRotateSpell.RotationDirection.CounterClockwise,sCard);
            }
        }

        return spell;
    }
}

1 个答案:

答案 0 :(得分:1)

每当我看到许多参数时,我认为可以改进一些东西。添加对依赖注入和新功能的有效关注只会使考虑您的选项变得更加重要,正如我所看到的那样,如下所示:

  1. 每家工厂都需要工单。强类型的一个基础并继承它,随着您已经熟悉的接口扩展。

    public interface ICastable()
    {
        bool ValidateTarget();
    
        // ICastable will require implementors to define Cast;
        // forcing a descendant (or the ancestor, I suppose) to
        // provide the details of how to cast that spell.  The parameter
        // is also a type that you control for spell-casting information
        void Cast(InvocationInfo info);
    }
    
    // really common info needed to cast a spell
    public class InvocationInfo
    {
        TargetableEntity Target;
        ControllableEntity SpellCaster;
        List<SpellRegents> ReagentsChosen;
        MoonPhases MoonPhase;
        bool IsMercuryInRetrograde;
    }
    
    // base spell class
    public class Spell
    {
        public string Name { get; set; }
        public int EnergyCost { get; set; }
    }
    
    // actual castable spell
    public class MagicMissile : Spell, ICastable
    {
        public void Cast(InvocationInfo details)
        {
            details.SpellCaster.SpendMana(this.EnergyCost);
    
            if (details.Target.Location.DistanceFrom(details.SpellCaster) > this.Range)
            {
                details.SpellCaster.SendMessage(Messages.OutOfRange);
                return;
            }
            // ...
        }
    }
    
  2. 不要忘记您可以使用通用类型:

    public Spell Hang<T>(InvocationInfo details) where T: Spell
    {
        if(details.SpellCaster.Energy < T.EnergyCost) 
            throw new InsufficientEnergyException();
    
        // ...
    }
    
    var spell = SpellFactory.Hang<Rotation>();
    
  3. 如果这听起来像是太多的工作,请考虑便宜的出路是动态类型,您可以为其分配任何您喜欢的内容并询问构造函数重载所需的内容。

  4. 在任何一种情况下,我怀疑多态性答案总是会更好。我总是建议解决方案坚持语言和框架的优势:强类型,面向对象,可读,简单。

    我会建议你,或者至少考虑正确的道路;你可以通过重载构造函数(或某种“make”方法)来降低重复和依赖性,同时如果你强烈地输入或弱化某种参数结构,那么就增加了可读性。