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

本文关键字:注入 实现 依赖 设计模式 工厂 | 更新日期: 2023-09-27 18:04:03

目前我正在尝试实现一些设计结构,工厂似乎是最合适的,就依赖注入而言,我更喜欢构造函数注入。然而,问题出现了,并不是所有的产品都需要相同的依赖关系,这有点混乱的模式…

我的抽象工厂.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法术工厂

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. 每个工厂都需要工单。强类型的一个基,继承它,扩展你已经熟悉的接口。

    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. 如果这听起来工作量太大,可以考虑一个便宜的方法是动态类型,你可以给它分配任何你喜欢的东西,并询问任何你的构造函数重载需要的东西。

在任何一种情况下,我怀疑多态答案总是会更好。我总是推荐遵循语言和框架优势的解决方案:强类型、面向对象、可读、简单。

我建议你走在正确的道路上,或者至少考虑走在正确的道路上;通过重载构造函数(或某种"make"方法)可以降低重复和依赖关系,同时如果对工厂类型进行强类型或弱类型的参数结构,则可以提高可读性。