我是一个自动化团队,为电子元器件设计测试。我们的框架迫切需要的一件事是为我们的驱动程序对象提供一个单一的源点,用于工作台上的各种测试设备(现在,驱动程序对象的创建是非常疯狂的)。
基本上,应该有一个对象,基于配置文件构建,它是所有其他测试代码根据名称字符串获取驱动程序对象的唯一位置。我这里叫它"DriverSource“。
问题是,这些驱动程序根本不存在类似的接口。一种可能是电源(使用"SetVoltage“和”SetCurrentLimit“等方法),另一种可能是数字万用表(使用"ReadVoltage”或“ReadCurrent”等方法)。
我想出的最佳解决方案是有一个具有以下声明的方法:
public object GetDriver(string name);然后,使用"DriverSource“对象的测试代码将调用该方法,然后将System.Object转换为正确的驱动类型(或者更准确地说,正确的驱动程序接口,如IPowerSupply)。
我认为这样的转换是可以接受的,因为无论什么测试代码将要使用这个驱动程序,最好知道接口是什么。但我希望能得到一些关于这是否是一种反模式的意见,等待着咬我。解决这一问题的任何更好的模式也将受到极大的赞赏。
最后一点:我认为这是显而易见的,但对于这个问题,性能基本上不是一个问题。在一次可以持续数小时的测试运行中,抓取驱动程序的次数将少于100次。
发布于 2015-07-17 02:54:33
如果您已经知道了类型,并且无论如何要转换为一个接口或类,那么更好的方法应该是将方法调用一个类型参数。
public T GetDriver<T>(string name);然后,可以使用工厂模式从方法中返回适当类型的对象。
public T GetDriver<T>(string name)
{
switch(typeof(T).Name)
{
case "Foo":
// Construct and return a Foo object
case "Bar":
// Construct and return a Bar object
case "Baz":
// Construct and return a Baz object
default:
return default(T);
}
}用法:
var driver = GetDriver<Foo>(someString); // Returns a Foo object发布于 2015-07-17 03:07:03
如果您真的想使此通用,我将使用工厂模式。
让我们从识别类型结构开始:
public interface IDriver
{
}
public interface IPowerSupply : IDriver
{
void SetVoltage();
void SetCurrent();
}
public interface IMultimeter : IDriver
{
double MeasureVoltage();
}您可以根据需要将其添加或移除。现在,我们需要一种让工厂自动发现正确类型并向其提供配置信息的方法。因此,让我们创建一个自定义属性:
public class DriverHandlerAttribute : Attribute
{
public Type DriverType { get; set; }
public string ConfigurationName { get; set; }
}然后我们需要一个存储配置数据的地方。此类型可以包含任何您想要的内容,比如从配置文件中加载的键/值字典:
public class Configuration
{
public string DriverName { get; set; }
public string OtherSetting { get; set; }
}最后,我们可以创建一个驱动程序。让我们创建一个IPowerSupply
[DriverHandler(DriverType = typeof(IPowerSupply), ConfigurationName="BaseSupply")]
public class BasePowerSupply : IPowerSupply
{
public BasePowerSupply(Configuration config) { /* ... */ }
public void SetVoltage() { /* ... */ }
public void SetCurrent() { /* ... */ }
}重要的是它是用属性修饰的,并且它有一个构造函数(尽管我创建了工厂,以便它也可以使用默认构造函数):
public static class DriverFactory
{
public static IDriver Create(Configuration config)
{
Type driverType = GetTypeForDriver(config.DriverName);
if (driverType == null) return null;
if (driverType.GetConstructor(new[] { typeof(Configuration) }) != null)
return Activator.CreateInstance(driverType, config) as IDriver;
else
return Activator.CreateInstance(driverType) as IDriver;
}
public static T Create<T>(Configuration config) where T : IDriver
{
return (T)Create(config);
}
private static Type GetTypeForDriver(string driverName)
{
var type = (from t in Assembly.GetExecutingAssembly().GetTypes()
let attrib = t.GetCustomAttribute<DriverHandlerAttribute>()
where attrib != null && attrib.ConfigurationName == driverName
select t).FirstOrDefault();
return type;
}
}为此,您需要读取配置数据(从XML加载、从服务读取、从文件等读取)。然后,可以创建如下所示的驱动程序:
var driver = DriverFactory.Create(configuration);
或者,如果您使用的是通用方法,并且您知道配置是用于电源,则可以调用:
var driver = DriverFactory.Create<IPowerSupply>(configuration);
在运行测试时,可以验证是否获得了正确的数据,例如,在测试方法中:
Assert.IsTrue(driver is IPowerSupply);
Assert.IsTrue(driver is BaseSupply);
Assert.DoesWhatever(((IPowerSupply)driver).SetVoltage());等等等等。
发布于 2015-07-17 03:21:25
我会用下面的代码:
public T GetDriver<T>(string name)
{
return ((Func<string, T>)_factories[typeof(T)])(name);
}_factories对象如下所示:
private Dictionary<Type, Delegate> _factories = new Dictionary<Type, Delegate>()
{
{ typeof(Foo), (Delegate)(Func<string, Foo>)(s => new Foo(s)) },
{ typeof(Bar), (Delegate)(Func<string, Bar>)(s => new Bar()) },
{ typeof(Baz), (Delegate)(Func<string, Baz>)(s => new Baz()) },
};基本上,_factories字典包含根据传入的string参数创建每个对象类型的所有代码。注意,在上面的示例中,Foo类将s作为构造函数参数。
然后,还可以在运行时对字典进行修改,以满足您的需要,而无需重新编译代码。
我甚至还会往前走一步。如果定义此工厂类:
public class Factory
{
private Dictionary<Type, Delegate> _factories = new Dictionary<Type, Delegate>();
public T Build<T>(string name)
{
return ((Func<string, T>)_factories[typeof(T)])(name);
}
public void Define<T>(Func<string, T> create)
{
_factories.Add(typeof(T), create);
}
}然后,您可以编写以下代码:
var drivers = new Factory();
drivers.Define(s => new Foo(s));
drivers.Define(s => new Bar());
drivers.Define(s => new Baz());
var driver = drivers.Build<Foo>("foo");我更喜欢这样。它是强类型的,在运行时很容易定制。
https://stackoverflow.com/questions/31467673
复制相似问题