3

だから私はデータベースからいくつかのデータを取得するプロジェクトに取り組んでいます-このプロジェクトを素晴らしいものにする2つのデータがあります.1つは私がタイプを持っています(それらはイベントと呼ばれますが、基本的には私が作成した.NETタイプに変換されます)そして、XMLを使用して、オブジェクトを設計したので、オブジェクトは適切に逆シリアル化されます。これはすべて素晴らしいものであり、単体テストが行​​われ、すべてのクラスとメソッドは単一責任の原則に従います。

私のアーキテクチャスキルが曖昧になるのは、XMLから作成した.NETオブジェクトを処理するためのビジネスロジックを構築するためのファクトリを作成しているときです。

基本的にこれは私が持っているものです。

  public class EventProcessorFactory : IEventProcessorFactory
    {
        private readonly List<IEventProcessor> _eventProcessors;

        public EventProcessorFactory()
        {
            _eventProcessors = new List<IEventProcessor>();
        }

        public IEventProcessor GetProcessor(Type eventType)
        {
            var typeOfEventProcessor = GetProcessorFromEventType(eventType);
            if (_eventProcessors.Any(x => x.GetType() == typeOfEventProcessor))
                return _eventProcessors.Single(x => x.GetType() == typeOfEventProcessor);
            var processor = BuildProcessorFromType(typeOfEventProcessor);
            _eventProcessors.Add(processor);
            return processor;
        }

        private static Type GetProcessorFromEventType(Type eventType)
        {
            if (eventType == typeof(EnrollmentEventType))
                return typeof(EnrollmentEventProcessor);
            if (eventType == typeof(ClaimantAccountInfoEventType))
                return typeof(ClaimantAccountInfoEventProcessor);
            if (eventType == typeof(PhoneUpdateEventType))
                return typeof(PhoneUpdateEventProcessor);
            if (eventType == typeof(AddressUpdateEventType))
                return typeof(AddressUpdateEventProcessor);
            if (eventType == typeof(ClientAccountInfoEventType))
                return typeof(ClientAccountInfoEventProcessor);
            return null;
        }

        private IEventProcessor BuildProcessorFromType(Type typeOfEventProcessor)
        {
            return ((IEventProcessor)Activator.CreateInstance(typeOfEventProcessor));
        }
    }

だからそれはうまくいくが、それはかなり不格好なようだ。工場の使用に関する記事をいくつか読んだことがありますが、正しいものを読んでいないか、理解できていません。上記のコードには2つの問題があります。

1)新しいイベントを追加して変更する必要がある場合は、後の開発者が「MyCoolNewEventType」と「MyCoolNewEventProcessor」を削除するだけで、イベントをプロセッサに一致させるメソッドを変更する必要がなくなります。

2)現在、インスタンスを作成すると、.CreateInstance();を呼び出すことができます。これは問題ありません。依存関係はありませんが、「イベントプロセッサ」は、少なくともデータベースに依存関係がある可能性があります。それを処理する方法が100%わからないので、Container.Resolve()をランダムに呼び出したくありません。

誰かが正しい方向を指すことができれば、それは途方もないことです。

4

4 に答える 4

4

あなたが探しているのは設定可能なファクトリです。これは、依存性注入フレームワーク、または最も簡単な方法で行うことができます-外部構成(xmlファイルが思い浮かびます)。これは、可能な実装のリストを格納し、オンデマンドでロード/変更されます。

このソリューションを使用すると、次のようなものになります

<Processors>
  <Processor dllname='' classname=''>
   ....
</Processors>

そして、.netが提供するリフレクション/任意のxml読み取り技術を使用してロードする必要があります。

于 2012-10-11T17:22:01.650 に答える
3

リフレクションを使用して、これらの属性にプロセッサタイプを設定できます。

[ProcessorType(typeof(EnrollmentEventProcessor)]
class EnrollmentEvent { ... }

簡単でクリーンなソリューション。Dictionary<Type, Object>そして、作成されたタイプについては、アクセスを高速化するためにを使用することをお勧めします。

于 2012-10-11T17:35:49.433 に答える
1

このシナリオでは、間違いなくDIで名前付きファクトリを使用しますが、Unityの経験はありません(私自身はAutofacの人です)。しかし、命名規則のアプローチを提案している人がいないことに少し驚いています。EventTypeの名前で、使用するプロセッサを決定します。プロセッサの名前が規則に従っている限り、新しいイベントタイプとプロセッサが追加されるため、これに追加のコードは必要ありません。

private static Type GetProcessorFromEventType(Type eventType)
{
    // Assuming phrase "Type" only is present at the end of the EventType name
    var processorName = eventType.Name.Replace("Type", "Processor");
    var processorType = Type.GetType(processorName);
    return processorType;
}

タイプとプロセッサが異なるアセンブリにある場合、名前からタイプを解決するメソッドを取得するのType.GetTypeはより困難になります。これが、このためにDIを使用する主な理由です。

于 2012-10-12T07:37:07.887 に答える
1

マッピングを保存する場所によって異なりますが、カスタム構成セクションを作成することもできます。

public class EventProcessorMapping : ConfigurationElement
{

    [ConfigurationProperty("event", IsRequired = true)]
    public string Event
    {
        get
        {
            return this["event"] as string;
        }
    }

    [ConfigurationProperty("processor", IsRequired = true)]
    public string Processor
    {
        get
        {
            return this["processor"] as string;
        }
    }
}

[ConfigurationCollection(typeof(EventProcessorMapping), CollectionType = ConfigurationElementCollectionType.AddRemoveClearMap)]
public class EventProcessors : ConfigurationElementCollection
{
    public EventProcessorMapping this[int index]
    {
        get
        {
            return BaseGet(index) as EventProcessorMapping;
        }
        set
        {
            if (BaseGet(index) != null)
            {
                BaseRemoveAt(index);
            }
            BaseAdd(index, value);
        }
    }

    protected override ConfigurationElement CreateNewElement()
    {
        return new EventProcessorMapping();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((EventProcessorMapping)element).Event;
    }
}

public class RegisterEventProcessorsConfig : ConfigurationSection
{

    public static RegisterEventProcessorsConfig GetConfig()
    {
        return (RegisterEventProcessorsConfig)ConfigurationManager.GetSection("RegisterEventProcessors") ?? new RegisterEventProcessorsConfig();
    }

    [ConfigurationProperty("EventProcessors")]
    public EventProcessors EventProcessors
    {
        get
        {
            var o = this["EventProcessors"];
            return o as EventProcessors;
        }
    }

}

次に、あなたApp.configはあなたが持つことができます:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="RegisterEventProcessors" type="UnitTestProject1.RegisterEventProcessorsConfig, UnitTestProject1"></section>
  </configSections>

  <RegisterEventProcessors>
    <EventProcessors>
      <add event="UnitTestProject1.ClaimantAccountInfoEventType, UnitTestProject1" processor="UnitTestProject1.ClaimantAccountInfoEventProcessor, UnitTestProject1" />
      <add event="UnitTestProject1.EnrollmentEventType, UnitTestProject1" processor="UnitTestProject1.EnrollmentEventProcessor, UnitTestProject1" />
    </EventProcessors>
  </RegisterEventProcessors>
</configuration>

したがって、少なくともマッピング構成を再配置します。ファクトリに関しては、ファクトリが作成されたときにProcessorクラスがインスタンス化されることを気にしない場合は、次のことができます。

public class EventProcessorFactory : IEventProcessorFactory
{
    private readonly Dictionary<Type, IEventProcessor> _eventProcessors;

    public EventProcessorFactory(IEnumerable<EventProcessorMapping> eventProcessorMappings)
    {
        _eventProcessors = new Dictionary<Type, IEventProcessor>();
        foreach (var mapping in eventProcessorMappings)
        {
            AddMapping(Type.GetType(mapping.Event), Type.GetType(mapping.Processor));
        }
    }

    public IEventProcessor GetProcessor<T>() where T : IEventType
    {
        return _eventProcessors[typeof(T)];
    }

    private void AddMapping(Type eventType, Type processorType)
    {
        var processor = (IEventProcessor)Activator.CreateInstance(processorType);
        _eventProcessors[eventType] = processor;
    }
}

コンストラクターでは、マッピング構成要素のコレクションを渡し、プロセッサーはその時点で作成され、プライベートコレクションに格納されます。次に、プロセッサを工場から入手することは、基本的には単なる辞書検索です。

2つの部分は次のようにまとめられます。

[TestMethod]
public void TestFactory()
{
    var config = RegisterEventProcessorsConfig.GetConfig();
    var factory = new EventProcessorFactory(config.EventProcessors.Cast<EventProcessorMapping>());

    var processor = factory.GetProcessor<EnrollmentEventType>();
    Assert.IsInstanceOfType(processor, typeof(EnrollmentEventProcessor));
}
于 2012-10-12T02:11:20.820 に答える