1

我在处理一些代码时遇到了一些设计问题:

我的代码基本如下所示:

主要的 COM 包装器:

public class MapinfoWrapper 
{
    public MapinfoWrapper()
    {
        Publics.InternalMapinfo = new MapinfoWrapper();
    }

    public void Do(string cmd) 
    {
        //Call COM do command
    }

    public string Eval(string cmd)
    {
        //Return value from COM eval command
    }
}

公共静态类保存对包装器的内部引用

internal static class Publics
{
    private static MapinfoWrapper _internalwrapper;
    internal static MapinfoWrapper InternalMapinfo 
    { 
        get
        {
            return _internalwrapper;     
        }
        set
        {
            _internalwrapper = value;
        }
    }
}

使用内部包装实例的代码:

    public class TableInfo
    {
        public string Name {
            get { return Publics.InternalMapinfo.Eval("String comman to get the name"); }
            set { Publics.InternalMapinfo.Do("String command to set the name"); }
        }
    }

这对任何人来说都难闻吗?我应该使用内部属性来保存对主包装对象的引用,还是应该在这里使用不同的设计?

注意: MapinfoWrapper 对象将被外部世界使用,所以我真的不想让它成为单例。

4

2 回答 2

2

您通过不将 MapInfoWrapper 注入类本身来降低 TableInfo 类的可测试性。是否使用这些 MapInfoWrapper 类的全局缓存取决于类 - 您需要确定是否有必要,但将包装器传递到 TableInfo 并在那里使用它而不是直接引用全局副本会改进您的设计在 TableInfo 方法中。结合接口的定义(即“重构接口”)执行此操作。

我还将在 Publics 的 getter(s) 中进行延迟实例化,以确保该对象在尚未创建时可用,而不是在 MapInfoWrapper 的构造函数中设置它。

public class TableInfo
{
     private IMapinfoWrapper wrapper;

     public TableInfo() : this(null) {}

     public TableInfo( IMapinfoWrapper wrapper )
     {
          // use from cache if not supplied, could create new here
          this.wrapper = wrapper ?? Publics.InternalMapInfo;
     }

     public string Name {
        get { return wrapper.Eval("String comman to get the name"); }
        set { wrapper.Do("String command to set the name"); }
     }
}

public interface IMapinfoWrapper
{
    void Do( string cmd );
    void Eval( string cmd );
}

public class MapinfoWrapper 
{
    public MapinfoWrapper()
    {
    }

    public void Do(string cmd) 
    {
        //Call COM do command
    }

    public string Eval(string cmd)
    {
        //Return value from COM eval command
    }
}

internal static class Publics
{
    private static MapinfoWrapper _internalwrapper;
    internal static MapinfoWrapper InternalMapinfo 
    { 
        get
        {
            if (_internalwrapper == null)
            {
                _internalwrapper = new MapinfoWrapper();
            }
            return _internalwrapper;     
        }
    }
}

现在,当您测试 TableInfo 方法时,您可以通过向构造函数提供您自己的实现来轻松模拟 MapInfoWrapper。前(假设一个手模拟):

[TestMethod]
[ExpectedException(typeof(ApplicationException))]
public void TestTableInfoName()
{
     IMapinfoWrapper mockWrapper = new MockMapinfoWrapper();
     mockWrapper.ThrowDoException(typeof(ApplicationException));

     TableInfo info = new TableInfo( mockWrapper );
     info.Do( "invalid command" );
}
于 2008-11-24T07:49:01.730 回答
0

我考虑将其添加到我的原始回复中,但这确实是一个不同的问题。

如果您存储和使用缓存副本,您可能需要考虑 MapinfoWrapper 类是否需要是线程安全的。每当您使用单个全局副本时,您都需要考虑一次是否会被多个线程使用并构建它,以便任何关键部分(任何可能更改或必须假定不更改的数据)都是线程-安全的。如果必须支持多线程环境(例如在网站中),那么这可能会反对使用单个全局副本,除非创建类的成本非常高。当然,如果你的类依赖于其他也不是线程安全的类,那么你可能需要让你的类成为线程安全的。

于 2008-11-24T08:05:27.157 回答