静态抽象方法的替代方法是什么?

发布于 2024-08-14 05:46:26 字数 2044 浏览 2 评论 0原文

我在尝试找出如何解决问题而无法在抽象类或接口中使用静态方法时遇到一些问题。考虑以下代码。我有很多继承自 AbsWizard 的 Wizard。每个向导都有一个 GetMagic(stringpell) 方法,该方法仅返回某些魔法词的魔法,但特定类型向导的所有实例都会响应同一组魔法词。

public abstract class AbsWizard
{
    public abstract Magic GetMagic(String magicword);
    public abstract string[] GetAvalibleSpells();
}

public class WhiteWizard : AbsWizard
{
    public override Magic GetMagic(string magicword)
    {
        //returns some magic based on the magic word
    }

    public override string[] GetAvalibleSpells()
    {
        string[] spells = {"booblah","zoombar"};
        return spells;
    }
}

public class BlackWizard : AbsWizard
{
    public override Magic GetMagic(string magicword)
    {
        //returns some magic based on the magic word
    }

    public override string[] GetAvalibleSpells()
    {
        string[] spells = { "zoogle", "xclondon" };
        return spells;
    }
}

我希望用户能够首先选择向导的类型,然后显示该类型的向导可以施展的法术列表。然后,当他们选择咒语时,程序将找到所选类型的所有(如果有的话)现有巫师,并让他们施展所选咒语。特定类型的所有巫师将始终具有相同的可用法术,并且我需要一种方法来确定特定类型的巫师可以施放的法术,而无需实际访问所选巫师类型的实例。

此外,我不想依赖于可能的向导类型或咒语的单独列表。相反,我宁愿通过 GetAvalibleSpells() 和反射来推断一切。例如我计划施展魔法如下:

    public static void CastMagic()
    {
        Type[] types = System.Reflection.Assembly.GetExecutingAssembly().GetTypes();
        List<Type> wizardTypes = new List<Type>();
        List<string> avalibleSpells = new List<string>();

        Type selectedWizardType;
        string selectedSpell;

        foreach (Type t in types)
        {
            if (typeof(AbsWizard).IsAssignableFrom(t))
            {
                wizardTypes.Add(t);
            }
        }

        //Allow user to pick a wizard type (assign a value to selectedWizardType)

        //find the spells the selected type of wizard can cast (populate availibleSpells)

        //Alow user to pick the spell (assign a value to  selectedSpell)

        //Find all instances, if any exsist, of wizards of type selectedWizardType and call GetMagic(selectedSpell);
    }

I'm having some problems trying to figure out how to solve a problem without being able to have static method in an abstract class or interface. Consider the following code. I have many Wizards that inherit from AbsWizard. Each wizard has a method GetMagic(string spell) that only returns magic for certain magic words, yet all instances of a specific type of wizard respond to the same set of magic words.

public abstract class AbsWizard
{
    public abstract Magic GetMagic(String magicword);
    public abstract string[] GetAvalibleSpells();
}

public class WhiteWizard : AbsWizard
{
    public override Magic GetMagic(string magicword)
    {
        //returns some magic based on the magic word
    }

    public override string[] GetAvalibleSpells()
    {
        string[] spells = {"booblah","zoombar"};
        return spells;
    }
}

public class BlackWizard : AbsWizard
{
    public override Magic GetMagic(string magicword)
    {
        //returns some magic based on the magic word
    }

    public override string[] GetAvalibleSpells()
    {
        string[] spells = { "zoogle", "xclondon" };
        return spells;
    }
}

I want the user to be able to first choose the type of wizard, and then be presented with a list of the spells that type of wizard can cast. Then when they choose a spell the program will find all, if any, existing wizards of the selected type and have them cast the selected spell. All wizards of a specific type will always have the same available spells, and I need a way to determine the spells a specific type of wizard can cast with out actually having access to an instance of the selected type of wizard.

In addition I don't want to have to depend on a separate list of possible wizard types or spells. Instead I would rather just infer everything through GetAvalibleSpells() and reflection. For example I plan to cast magic as follows:

    public static void CastMagic()
    {
        Type[] types = System.Reflection.Assembly.GetExecutingAssembly().GetTypes();
        List<Type> wizardTypes = new List<Type>();
        List<string> avalibleSpells = new List<string>();

        Type selectedWizardType;
        string selectedSpell;

        foreach (Type t in types)
        {
            if (typeof(AbsWizard).IsAssignableFrom(t))
            {
                wizardTypes.Add(t);
            }
        }

        //Allow user to pick a wizard type (assign a value to selectedWizardType)

        //find the spells the selected type of wizard can cast (populate availibleSpells)

        //Alow user to pick the spell (assign a value to  selectedSpell)

        //Find all instances, if any exsist, of wizards of type selectedWizardType and call GetMagic(selectedSpell);
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

尘曦 2024-08-21 05:46:26

我认为这是非常糟糕的风格。您编写了代码,因此您应该知道其中有哪些向导类。通过反射运行所有类型并检查它们是否派生自 AbsWizard 的方式非常糟糕(而且很慢!)。

I think this is very bad style. You write the code, so you should know what wizard-classes you have in there. It's very bad style (and slow!) to run through all types via reflection and check if they derive from AbsWizard.

预谋 2024-08-21 05:46:26

托管扩展性框架(可通过 .NET-4.0 之前版本的 codeplex 或内置 .NET 4.0 获得)在 System.ComponentModel.Composition 命名空间)就是为此构建的。假设您有一个服务,它可以要求用户选择一个向导,然后创建它。它使用向导提供者来创建向导,并且需要知道提供者创建的向导的名称和可用咒语(元数据)。您可能会使用如下接口:

namespace Wizardry
{
    using System.Collections.Generic;

    public interface IWizardProvider
    {
        IWizard CreateWizard();
    }

    public interface IWizard
    {
        IMagic GetMagic(string magicWord);
    }

    public interface IWizardProviderMetadata
    {
        string Name { get; }

        IEnumerable<string> Spells { get; }
    }
}

向导创建服务导入可用的向导提供程序,通过某种机制(在您的情况下为用户反馈)选择一个提供程序,并使用该提供程序来创建向导。

namespace Wizardry
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.Linq;

    public class UserWizardCreationService
    {
        [Import]
        private IEnumerable<Lazy<IWizardProvider, IWizardProviderMetadata>> WizardProviders { get; set; }

        public IWizard CreateWizard()
        {
            IWizard wizard = null;
            Lazy<IWizardProvider, IWizardProviderMetadata> lazyWizardProvider = null;
            IWizardProvider wizardProvider = null;

            // example 1: get a provider that can create a "White Wizard"
            lazyWizardProvider = WizardProviders.FirstOrDefault(provider => provider.Metadata.Name == "White Wizard");
            if (lazyWizardProvider != null)
                wizardProvider = lazyWizardProvider.Value;

            // example 2: get a provider that can create a wizard that can cast the "booblah" spell
            lazyWizardProvider = WizardProviders.FirstOrDefault(provider => provider.Metadata.Spells.Contains("booblah"));
            if (lazyWizardProvider != null)
                wizardProvider = lazyWizardProvider.Value;

            // finally, for whatever wizard provider we have, use it to create a wizard
            if (wizardProvider != null)
                wizard = wizardProvider.CreateWizard();

            return wizard;
        }
    }
}

然后,您可以创建并导出任意数量的带有咒语的向导提供者,并且创建服务将能够找到它们:

namespace Wizardry
{
    using System.ComponentModel.Composition;

    [Export(typeof(IWizardProvider))]
    [Name("White Wizard")]
    [Spells("booblah", "zoombar")]
    public class WhiteWizardProvider : IWizardProvider
    {
        public IWizard CreateWizard()
        {
            return new WhiteWizard();
        }
    }

    [Export(typeof(IWizardProvider))]
    [Name("White Wizard")]
    [Spells("zoogle", "xclondon")]
    public class BlackWizardProvider : IWizardProvider
    {
        public IWizard CreateWizard()
        {
            return new BlackWizard();
        }
    }
}

当然,您还需要实现向导。

namespace Wizardry
{
    using System;

    public class WhiteWizard : IWizard
    {
        public IMagic GetMagic(string magicWord)
        {
            throw new NotImplementedException();
        }
    }

    public class BlackWizard : IWizard
    {
        public IMagic GetMagic(string magicWord)
        {
            throw new NotImplementedException();
        }
    }
}

为了保持简洁,此代码使用自定义 NameAttributeSpellsAttribute 作为比 ExportMetadataAttribute

namespace Wizardry
{
    using System;

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
    public abstract class MultipleBaseMetadataAttribute : Attribute
    {
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public abstract class SingletonBaseMetadataAttribute : Attribute
    {
    }

    public sealed class NameAttribute : SingletonBaseMetadataAttribute
    {
        public NameAttribute(string value) { this.Name = value; }
        public string Name { get; private set; }
    }

    public sealed class SpellsAttribute : MultipleBaseMetadataAttribute
    {
        public SpellsAttribute(params string[] value) { this.Spells = value; }
        public string[] Spells { get; private set; }
    }
}

The Managed Extensibility Framework (available through codeplex for pre-.NET-4.0, or built-in .NET 4.0 in the System.ComponentModel.Composition namespace) was built for this. Say you have a service that can ask a user to select a wizard and then create it. It uses a wizard provider to create the wizards, and needs to know the name and available spells (metadata) for the wizards that a provider creates. You might use interfaces like these:

namespace Wizardry
{
    using System.Collections.Generic;

    public interface IWizardProvider
    {
        IWizard CreateWizard();
    }

    public interface IWizard
    {
        IMagic GetMagic(string magicWord);
    }

    public interface IWizardProviderMetadata
    {
        string Name { get; }

        IEnumerable<string> Spells { get; }
    }
}

The wizard creation service imports the available wizard providers, selects one through some mechanism (user feedback in your case), and uses the provider to create the wizard.

namespace Wizardry
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.Linq;

    public class UserWizardCreationService
    {
        [Import]
        private IEnumerable<Lazy<IWizardProvider, IWizardProviderMetadata>> WizardProviders { get; set; }

        public IWizard CreateWizard()
        {
            IWizard wizard = null;
            Lazy<IWizardProvider, IWizardProviderMetadata> lazyWizardProvider = null;
            IWizardProvider wizardProvider = null;

            // example 1: get a provider that can create a "White Wizard"
            lazyWizardProvider = WizardProviders.FirstOrDefault(provider => provider.Metadata.Name == "White Wizard");
            if (lazyWizardProvider != null)
                wizardProvider = lazyWizardProvider.Value;

            // example 2: get a provider that can create a wizard that can cast the "booblah" spell
            lazyWizardProvider = WizardProviders.FirstOrDefault(provider => provider.Metadata.Spells.Contains("booblah"));
            if (lazyWizardProvider != null)
                wizardProvider = lazyWizardProvider.Value;

            // finally, for whatever wizard provider we have, use it to create a wizard
            if (wizardProvider != null)
                wizard = wizardProvider.CreateWizard();

            return wizard;
        }
    }
}

You can then create and export an arbitrary number of wizard providers with spells, and the creation service will be able to find them:

namespace Wizardry
{
    using System.ComponentModel.Composition;

    [Export(typeof(IWizardProvider))]
    [Name("White Wizard")]
    [Spells("booblah", "zoombar")]
    public class WhiteWizardProvider : IWizardProvider
    {
        public IWizard CreateWizard()
        {
            return new WhiteWizard();
        }
    }

    [Export(typeof(IWizardProvider))]
    [Name("White Wizard")]
    [Spells("zoogle", "xclondon")]
    public class BlackWizardProvider : IWizardProvider
    {
        public IWizard CreateWizard()
        {
            return new BlackWizard();
        }
    }
}

Of course you'll need to implement the wizards as well.

namespace Wizardry
{
    using System;

    public class WhiteWizard : IWizard
    {
        public IMagic GetMagic(string magicWord)
        {
            throw new NotImplementedException();
        }
    }

    public class BlackWizard : IWizard
    {
        public IMagic GetMagic(string magicWord)
        {
            throw new NotImplementedException();
        }
    }
}

To keep things clean, this code uses a custom NameAttribute and SpellsAttribute as a much cleaner form of exporting metadata than ExportMetadataAttribute:

namespace Wizardry
{
    using System;

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
    public abstract class MultipleBaseMetadataAttribute : Attribute
    {
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public abstract class SingletonBaseMetadataAttribute : Attribute
    {
    }

    public sealed class NameAttribute : SingletonBaseMetadataAttribute
    {
        public NameAttribute(string value) { this.Name = value; }
        public string Name { get; private set; }
    }

    public sealed class SpellsAttribute : MultipleBaseMetadataAttribute
    {
        public SpellsAttribute(params string[] value) { this.Spells = value; }
        public string[] Spells { get; private set; }
    }
}
凉城 2024-08-21 05:46:26

添加另一个间接级别。 GetAvailableSpells 方法并不是真正的实例方法,因为它对于所有实例都是相同的。正如您所指出的,您不能拥有抽象静态方法,因此请将特定于类型的内容移至基于实例的类工厂中。在下面的示例中,AvailableSpellsMagicSchool 抽象类的一个方法,该抽象类具有具体子类 BlackMagicWhiteMagic Wizard 也有子类型,但每个 Wizard 都可以返回它所属的 MagicSchool,为您提供类型安全的,与类型无关的方式来找出任何给定 Wizard 对象的咒语,无需单独的表或代码重复。

public abstract class MagicSchool
{
    public abstract string[] AvailableSpells { get; }
    public abstract Wizard CreateWizard();
}

public abstract class Wizard
{
    protected Wizard(MagicSchool school)
    {
        School = school;
    }

    public abstract Cast(string spell);

    MagicSchool School 
    {
        public get; 
        protected set;
    }
}

public class BlackMagic : MagicSchool
{
    public override AvailableSpells
    {
        get
        {
            return new string[] { "zoogle", "xclondon" };
        }
    }

    public override Wizard CreateWizard()
    {
        return new BlackWizard(this);
    }
}

public class BlackWizard : Wizard
{
    public BlackWizard(BlackMagic school)
        : base(school)
    {
        // etc
    }

    public override Cast(string spell)
    {
        // etc.
    }
}

// continue for other wizard types

Add another level of indirection. The GetAvailableSpells method isn't really an instance method, since it's the same for all instances. As you pointed you, you can't have an abstract static method, so instead move the type-specific stuff into an instance-based class factory. In the example below, AvailableSpells is a method of the MagicSchool abstract class, which has concrete subclasses BlackMagic, WhiteMagic, etc. The Wizard also has sub-types, but every Wizard can return the MagicSchool that it belongs to, giving you a type-safe, type-independent way to find out what the spells for any given Wizard object are without separate tables or code duplication.

public abstract class MagicSchool
{
    public abstract string[] AvailableSpells { get; }
    public abstract Wizard CreateWizard();
}

public abstract class Wizard
{
    protected Wizard(MagicSchool school)
    {
        School = school;
    }

    public abstract Cast(string spell);

    MagicSchool School 
    {
        public get; 
        protected set;
    }
}

public class BlackMagic : MagicSchool
{
    public override AvailableSpells
    {
        get
        {
            return new string[] { "zoogle", "xclondon" };
        }
    }

    public override Wizard CreateWizard()
    {
        return new BlackWizard(this);
    }
}

public class BlackWizard : Wizard
{
    public BlackWizard(BlackMagic school)
        : base(school)
    {
        // etc
    }

    public override Cast(string spell)
    {
        // etc.
    }
}

// continue for other wizard types
一片旧的回忆 2024-08-21 05:46:26

首先,您应该真正考虑是否不能改变不使用巫师实例来发现其可用咒语的规则。我发现 原型模式 对于这类事情实际上非常有用。

但是,如果您确实无法做到这一点,您可以使用嵌套类和反射来发现特定具体 AbsWizard 派生体可以施放的可用咒语。这是一个例子:

public abstract class AbsWizard
{
    public abstract Magic GetMagic(String magicword);
    public abstract string[] GetAvalibleSpells();
}

public class WhiteWizard : AbsWizard
{
    // organizes all the spells available to the wizard...
    public sealed class Spells
    {
        // NOTE: Spells may be better off as a specific class, rather than as strings.
        // Then you could decorate them with a lot of other information (cost, category, etc).
        public const string Abracadabra = "Abracadabra";
        public const string AlaPeanutButterSandwiches = "APBS";
    }
}

public static void CastMagic()
{
    Type[] types = System.Reflection.Assembly.GetExecutingAssembly().GetTypes();
    List<Type> wizardTypes = new List<string>();
    List<string> avalibleSpells = new List<string>();

    Type selectedWizardType;
    string selectedSpell;

    foreach (Type t in types)
    {
        if (typeof(AbsWizard).IsAssignableFrom(t))
        {
            // find a nested class named Spells and search it for public spell definitions
            // better yet, use an attribute to decorate which class is the spell lexicon
            var spellLexicon = Type.FromName( t.FullName + "+" + "Spells" );
            foreach( var spellField in spellLexicon.GetFields() )
               // whatever you do with the spells...
        }
    }
}

有很多方法可以改进上面的代码。

首先,您可以定义自己的自定义属性,您可以在每个向导的嵌套类上标记该属性以识别拼写词典。

其次,使用字符串来定义可用的咒语可能最终会受到一些限制。您可能会发现定义所有可用咒语的全局静态列表更容易(作为某种类,我们将其称为Spell)。然后,您可以根据此列表而不是字符串来定义向导的可用咒语。

第三,考虑为这个东西创建一个外部配置,而不是嵌入的嵌套类。它更灵活并且可能更容易维护。然而,编写如下代码可能会很好:

WhiteWizard.Spells.Abracadabra.Cast();

最后,考虑为每个向导派生创建一个静态字典来管理可用咒语列表,以便您可以避免多次执行反射(这是昂贵的)。

First, you should really consider whether you can't bend the rules of not using instances of Wizards to discover their available spells. I find that the prototype pattern can actually be quite useful for this sort of thing.

However, if you really can't do that, you can use nested classes and reflection to discover the available spells that a particular concrete AbsWizard-derivative can cast. Here's an example:

public abstract class AbsWizard
{
    public abstract Magic GetMagic(String magicword);
    public abstract string[] GetAvalibleSpells();
}

public class WhiteWizard : AbsWizard
{
    // organizes all the spells available to the wizard...
    public sealed class Spells
    {
        // NOTE: Spells may be better off as a specific class, rather than as strings.
        // Then you could decorate them with a lot of other information (cost, category, etc).
        public const string Abracadabra = "Abracadabra";
        public const string AlaPeanutButterSandwiches = "APBS";
    }
}

public static void CastMagic()
{
    Type[] types = System.Reflection.Assembly.GetExecutingAssembly().GetTypes();
    List<Type> wizardTypes = new List<string>();
    List<string> avalibleSpells = new List<string>();

    Type selectedWizardType;
    string selectedSpell;

    foreach (Type t in types)
    {
        if (typeof(AbsWizard).IsAssignableFrom(t))
        {
            // find a nested class named Spells and search it for public spell definitions
            // better yet, use an attribute to decorate which class is the spell lexicon
            var spellLexicon = Type.FromName( t.FullName + "+" + "Spells" );
            foreach( var spellField in spellLexicon.GetFields() )
               // whatever you do with the spells...
        }
    }
}

There are many ways to improve the above code.

First, you can define your own custom attribute that you can tag on the nested classes of each wizard to identify the spell lexicon.

Second, using strings to define the available spells may end up being a bit limiting. You may find it easier to define a global static list of all available spells (as some kind of class, let's call it Spell). You could then define the available spells of the wizard based off this list, rather than strings.

Third, consider creating an external configuration for this thing rather than embedded, nested classes. It's more flexible and possibly easier to maintain. However, it can be nice to write code like:

WhiteWizard.Spells.Abracadabra.Cast();

Finally, consider creating a static dictionary for each Wizard-derivative that manages the list of available spells so that you can avoid performing reflection (which is expensive) more than once.

最美的太阳 2024-08-21 05:46:26

由于咒语与向导的类型相关,因此我将通过属性来执行此操作:

[AttributeUsage(AttributeTargets.Class)]
public class SpellsAttribute : Attribute
{
    private string[] spells;
    public WizardAttribute(params string[] spells)
    {
        this.spells = spells;
    }

    public IEnumerable<string> Spells
    {
        get { return this.spells ?? Enumerable.Empty<string>(); }
    }
}

然后您声明一个向导类型,如下所示:

[Spells("booblah","zoombar")]
public class WhiteWizard : AbsWizard
{
    public override Magic GetMagic(string magicWord) { ... }
}

然后从程序集中加载向导类型的类可以检查每个向导类是否具有此属性,如果是这样,则使可用的类型(或引发异常)。

Since spells are tied to the type of the wizard, I'd do this through attributes:

[AttributeUsage(AttributeTargets.Class)]
public class SpellsAttribute : Attribute
{
    private string[] spells;
    public WizardAttribute(params string[] spells)
    {
        this.spells = spells;
    }

    public IEnumerable<string> Spells
    {
        get { return this.spells ?? Enumerable.Empty<string>(); }
    }
}

Then you declare a wizard type like this:

[Spells("booblah","zoombar")]
public class WhiteWizard : AbsWizard
{
    public override Magic GetMagic(string magicWord) { ... }
}

Then the class that loads wizard types from the assembly can check each wizard class has this attribute and if so makes the type available (or throws an exception).

甜是你 2024-08-21 05:46:26

这能满足您的需要吗?根据需要将每种类型的向导添加到工厂。向导永远不会在您的库之外实例化,而只会在库内实例化。对于图书馆外的人来说,要获得巫师,他们会致电工厂以获取支持给定咒语的巫师。工厂自己设立。只需向工厂注册每个新向导即可。

public class Magic
{
}

public abstract class AbsWizard
{
    public abstract Magic GetMagic(String magicword);
    public abstract string[] GetAvalibleSpells();

    internal AbsWizard()
    {
    }
}

public class WhiteWizard : AbsWizard
{
    public override Magic GetMagic(string magicword)
    {
        return new Magic();
    }

    public override string[] GetAvalibleSpells()
    {
        string[] spells = { "booblah", "zoombar" };
        return spells;
    }
}


public static class WizardFactory
{
    private static Dictionary<string, List<AbsWizard>> _spellsList = new Dictionary<string, List<AbsWizard>>();

    /// <summary>
    /// Take the wizard and add his spells to the global spell pool.  Then register him with that spell.
    /// </summary>
    /// <param name="wizard"></param>
    private static void RegisterWizard(AbsWizard wizard)
    {
        foreach (string s in wizard.GetAvalibleSpells())
        {
            List<AbsWizard> lst = null;
            if (!_spellsList.TryGetValue(s, out lst))
            {
                _spellsList.Add(s, lst = new List<AbsWizard>());
            }
            lst.Add(wizard);
        }
    }

    public string[] GetGlobalSpellList()
    {
        List<string> retval = new List<string>();
        foreach (string s in _spellsList.Keys)
        {
            retval.Add(s);
        }
        return retval.ToArray<string>();
    }

    public List<AbsWizard> GetWizardsWithSpell(string spell)
    {
        List<AbsWizard> retval = null;
        _spellsList.TryGetValue(spell, out retval);
        return retval;
    }

    static WizardFactory()
    {
        RegisterWizard(new WhiteWizard());
    }
}

Does this do what you need? Add each type of wizard to the factory as needed. Wizards will never be instantiated outside of your library, only inside it. For someone outside your library to get a wizard, they make a call to the factory to get those wizards that support a given spell. The factory sets itself up. Just register each new wizard with the factory.

public class Magic
{
}

public abstract class AbsWizard
{
    public abstract Magic GetMagic(String magicword);
    public abstract string[] GetAvalibleSpells();

    internal AbsWizard()
    {
    }
}

public class WhiteWizard : AbsWizard
{
    public override Magic GetMagic(string magicword)
    {
        return new Magic();
    }

    public override string[] GetAvalibleSpells()
    {
        string[] spells = { "booblah", "zoombar" };
        return spells;
    }
}


public static class WizardFactory
{
    private static Dictionary<string, List<AbsWizard>> _spellsList = new Dictionary<string, List<AbsWizard>>();

    /// <summary>
    /// Take the wizard and add his spells to the global spell pool.  Then register him with that spell.
    /// </summary>
    /// <param name="wizard"></param>
    private static void RegisterWizard(AbsWizard wizard)
    {
        foreach (string s in wizard.GetAvalibleSpells())
        {
            List<AbsWizard> lst = null;
            if (!_spellsList.TryGetValue(s, out lst))
            {
                _spellsList.Add(s, lst = new List<AbsWizard>());
            }
            lst.Add(wizard);
        }
    }

    public string[] GetGlobalSpellList()
    {
        List<string> retval = new List<string>();
        foreach (string s in _spellsList.Keys)
        {
            retval.Add(s);
        }
        return retval.ToArray<string>();
    }

    public List<AbsWizard> GetWizardsWithSpell(string spell)
    {
        List<AbsWizard> retval = null;
        _spellsList.TryGetValue(spell, out retval);
        return retval;
    }

    static WizardFactory()
    {
        RegisterWizard(new WhiteWizard());
    }
}
纸伞微斜 2024-08-21 05:46:26

使用工厂类来实例化您的向导。工厂有一个

public static string[] GetSpellsForWizardType(Type wizardType)

方法可以让你确定巫师可以施展哪些法术。工厂还调用相同的方法来构造一个新的向导实例并设置其法术集。

Use a factory class to instantiate your wizards. The factory has a

public static string[] GetSpellsForWizardType(Type wizardType)

method that allows you to determine which spells a wizard can cast. The factory also calls this same method to construct a new wizard instance and set its spell set.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文