首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >此方法返回System.Object类是反模式吗?

此方法返回System.Object类是反模式吗?
EN

Stack Overflow用户
提问于 2015-07-17 02:45:03
回答 3查看 214关注 0票数 7

我是一个自动化团队,为电子元器件设计测试。我们的框架迫切需要的一件事是为我们的驱动程序对象提供一个单一的源点,用于工作台上的各种测试设备(现在,驱动程序对象的创建是非常疯狂的)。

基本上,应该有一个对象,基于配置文件构建,它是所有其他测试代码根据名称字符串获取驱动程序对象的唯一位置。我这里叫它"DriverSource“。

问题是,这些驱动程序根本不存在类似的接口。一种可能是电源(使用"SetVoltage“和”SetCurrentLimit“等方法),另一种可能是数字万用表(使用"ReadVoltage”或“ReadCurrent”等方法)。

我想出的最佳解决方案是有一个具有以下声明的方法:

代码语言:javascript
复制
public object GetDriver(string name);

然后,使用"DriverSource“对象的测试代码将调用该方法,然后将System.Object转换为正确的驱动类型(或者更准确地说,正确的驱动程序接口,如IPowerSupply)。

我认为这样的转换是可以接受的,因为无论什么测试代码将要使用这个驱动程序,最好知道接口是什么。但我希望能得到一些关于这是否是一种反模式的意见,等待着咬我。解决这一问题的任何更好的模式也将受到极大的赞赏。

最后一点:我认为这是显而易见的,但对于这个问题,性能基本上不是一个问题。在一次可以持续数小时的测试运行中,抓取驱动程序的次数将少于100次。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-07-17 02:54:33

如果您已经知道了类型,并且无论如何要转换为一个接口或类,那么更好的方法应该是将方法调用一个类型参数。

代码语言:javascript
复制
public T GetDriver<T>(string name);

然后,可以使用工厂模式从方法中返回适当类型的对象。

代码语言:javascript
复制
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);
    }
}

用法:

代码语言:javascript
复制
var driver = GetDriver<Foo>(someString); // Returns a Foo object
票数 7
EN

Stack Overflow用户

发布于 2015-07-17 03:07:03

如果您真的想使此通用,我将使用工厂模式。

让我们从识别类型结构开始:

代码语言:javascript
复制
public interface IDriver
{
}

public interface IPowerSupply : IDriver
{
    void SetVoltage();
    void SetCurrent();
}

public interface IMultimeter : IDriver
{
    double MeasureVoltage();
}

您可以根据需要将其添加或移除。现在,我们需要一种让工厂自动发现正确类型并向其提供配置信息的方法。因此,让我们创建一个自定义属性:

代码语言:javascript
复制
public class DriverHandlerAttribute : Attribute
{
    public Type DriverType { get; set; }
    public string ConfigurationName { get; set; }
}

然后我们需要一个存储配置数据的地方。此类型可以包含任何您想要的内容,比如从配置文件中加载的键/值字典:

代码语言:javascript
复制
public class Configuration
{
    public string DriverName { get; set; }
    public string OtherSetting { get; set; }
}

最后,我们可以创建一个驱动程序。让我们创建一个IPowerSupply

代码语言:javascript
复制
[DriverHandler(DriverType = typeof(IPowerSupply), ConfigurationName="BaseSupply")]
public class BasePowerSupply : IPowerSupply
{
    public BasePowerSupply(Configuration config) { /* ... */ }

    public void SetVoltage() { /* ... */ }

    public void SetCurrent() { /* ... */ }
}

重要的是它是用属性修饰的,并且它有一个构造函数(尽管我创建了工厂,以便它也可以使用默认构造函数):

代码语言:javascript
复制
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);

在运行测试时,可以验证是否获得了正确的数据,例如,在测试方法中:

代码语言:javascript
复制
Assert.IsTrue(driver is IPowerSupply);
Assert.IsTrue(driver is BaseSupply);
Assert.DoesWhatever(((IPowerSupply)driver).SetVoltage());

等等等等。

票数 2
EN

Stack Overflow用户

发布于 2015-07-17 03:21:25

我会用下面的代码:

代码语言:javascript
复制
public T GetDriver<T>(string name)
{
    return ((Func<string, T>)_factories[typeof(T)])(name);
}

_factories对象如下所示:

代码语言:javascript
复制
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作为构造函数参数。

然后,还可以在运行时对字典进行修改,以满足您的需要,而无需重新编译代码。

我甚至还会往前走一步。如果定义此工厂类:

代码语言:javascript
复制
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);
    }
}

然后,您可以编写以下代码:

代码语言:javascript
复制
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");

我更喜欢这样。它是强类型的,在运行时很容易定制。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31467673

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档