-
首先,我们的应用程序或“shell”需要对“可用”方法进行显式枚举。我们可以提供任何我们想要的方式,无论是显式(通过配置)还是隐式(通过反射)。作为一种偏好,我更喜欢前者,因为它不那么“神奇”。
-
到第二点,除了显式枚举之外,我们的shell还必须维护从选择到实现的映射。同样,这可以通过多种方式实现,但通常我们的枚举是一个“类型”列表,当选择了一个类型时,我们从工厂请求实现该类型。实现这种模式最简单的方法是利用控制容器的反转,如Castle Windsor、Unity、Ninject等。老实说,我不记得我们在内部使用了什么。
例如,考虑一下,
// a simple Plain Old C Object that describes business methods.
public class BusinessMethod
{
// user-friendly name
public string Name { get; set; }
// type that actually implements
public Type ImplementationType { get; set; }
}
// ... meanwhile, back on the ranch ...
public void OnBusinessMethodSelection ()
{
// 1. if selected
if (BusinessMethodList.SelectedItem != null)
{
// 2. retrieve selected item
BusinessMethod selected =
(BusinessMethod)(BusinessMethodList.SelectedItem);
// 3. request implementation of selected item from
// IoC container
object implementation =
_container.Resolve (selected.ImplementationType);
}
}
-
到你的第三点,我们需要一种不同部分的沟通方式。不幸的是,我们不能依赖于设计时方法(即命令和数据绑定),因此我们必须实现自己的事件聚合服务。基本上是“单例”(如在单例中
不
静态类)了解订阅服务器和发布服务器,最好是提供强类型参数的实现。对我们来说,幸运的是,许多更伟大的人已经走在我们前面,我们可能从他们的经历中获益。看看肯特·布加特的
Event Hub
.
下面是一个如何使用事件聚合器的示例
// an example of a strongly typed subject. notice how subject
// defines content. semanticly, when someone creates and publishes
// an instance of this subject, they are requesting someone show
// an analysis view based on data content,
public class AnalysisSubject
{
// subject content, in this case a data result from
// a business method
public object Data { get; set; }
}
public class MainWindow : ISubscriber<AnalysisSubject> ...
{
// use whatever implementation of an IoC container we like
// here i assume we abstract from implementation and use a
// custom interface IContainer that exposes functionality
// that we need
private readonly IContainer _container = null;
public class MainWindow ()
{
// we're teh r00tz! we create an instance of IoC
// container for use throughout application
IContainer _container = new CustomContainer ();
// our container exposes both parameterized and
// type-parameterized resolve methods
IEventHub events = _container.Resolve<IEventHub> ();
events.Subscribe<AnalysisSubject> (this);
}
#region ISubscriber<AnalysisSubject>
// part of strongly typed subscriptions is that we
// may now handle strongly typed publications! yay!
public void Receive (AnalysisSubject subject)
{
// 1. request to display analysis of data
Type analysisType = subject.Data.GetType ();
// 2. get view control based on payload type
//
// NOTE: implicit usage below is not consistent
// with previous invocations, here we are submitting
// a type of something we already have, and actually
// want back something that knows how to handle it.
// most IoC containers can provide this functionality
// through "facilities" add ons that accept a
// parameter\discriminator like below, and produce
// something in return.
Control control = (Control)(_container.Resolve (analysisType));
// [alternatively] if the above is too "magical" where
// IAnalysisFactory is an interface we define for this
// express purpose
//IAnalysisFactory factory = _container.Resolve<IAnalysisFactory> ();
//Control control = factory.GetAnalysisControlFor (analysisType);
// 3. assign subject data to control
Control.DataContext = subject.Data;
// 4. display control
}
#endregion
}
以及出版物的一个例子
public class SomeBusinessView
{
private readonly IEventHub _events = null;
// we cannot function without an event aggregator of
// some kind, so we declare our dependency as a contructor
// dependency
public SomeBusinessView (IEventHub events)
{
_events = events;
}
public void DoMyThang ()
{
// 1. do some business
MyBusinessData data = SomeBusinessFunction ();
// 2. publish complete event
AnalysisSubject subject = new AnalysisSubject () { Data = data, };
_events.Publish (subject);
}
}