Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#接口设计,公开库类?_C#_Oop_Architecture_Interface - Fatal编程技术网

C#接口设计,公开库类?

C#接口设计,公开库类?,c#,oop,architecture,interface,C#,Oop,Architecture,Interface,我想定义一个接口“IFile”,它包含一个键/值对数组“Metadata”。当获取或设置这些键/值对时,IFile实现者应该能够采取行动。最好的办法是什么?我看到三种方法: 方法1)获取/设置字典对象: public interface IFile { ... Dictionary<String, String> GetMetadata(); void SetMetadata(Dictionary<String, String> metadat

我想定义一个接口“IFile”,它包含一个键/值对数组“Metadata”。当获取或设置这些键/值对时,IFile实现者应该能够采取行动。最好的办法是什么?我看到三种方法:

方法1)获取/设置字典对象:

public interface IFile
{
    ...

    Dictionary<String, String> GetMetadata();

    void SetMetadata(Dictionary<String, String> metadata);
}
在IFile的实现中,可以提供作用于get/set的继承版本的Dictionary

方法3)完全避免使用字典,并提供自定义接口,例如:

public interface IMetadata
{
    String GetValue(String key);        
    void SetValue(String key, String value);        
    Boolean Contains(String key);        
    void Delete(String key);  

    ...
}

public interface IFile
{
    ...

    IMetadata Metadata();
}
我倾向于方法3,因为它让实现者决定如何实际实现元数据数据结构。其他的解决办法是使用字典。然而,方法3似乎涉及很多额外的包装代码

我感觉到在设计类层次结构时,在这个问题的背后有一个更深层次的困境,即是直接公开库类,还是公开一些隐藏内部使用的库类的包装函数。我在OOP设计方面几乎没有实际经验,所以在这方面,我非常欢迎关于“正确方法”的建议

谢谢


Lars

如果您担心的是从键值对字典中强制继承,那么为什么不使用IDictionary呢


那么您的第一种方法是可行的。

如果元数据的类型在编译时已知,那么我个人可能会选择以下方法:

public interface IFile
{
    ...

    IDictionary<string, string> Metadata { get; }
}
公共接口IFile
{
...
IDictionary元数据{get;}
}
注意-IDictionary而不是Dictionary-这让实现类决定使用哪种类型的Dictionary实现

(我使用字符串作为dictionary类型的示例,也因为这是您用于imeadata的类型-如有必要,请更改以满足您的需要)

ps-如果元数据的键范围是固定的且相对较小,则将键设置为枚举-这比字符串比较更有效。

我喜欢选项3(在接口中定义方法),因为:

  • 它不会强制实现 使用特定的数据结构
  • 它更易于测试/模拟
  • 方法4:

    public class JFile
    {
        ...
    
        protected Dictionary Metadata() { ... }
    
        ...
    
        // --> all this use "Dictionary" internally
        // --> but, do somthing to other "IFile" fields
    
        public String GetValue(String key) { ... }
        public void SetValue(String key, String value)  { ... }
        public Boolean Contains(String key)  { ... }
        public void Delete(String key)  { ... }
    }
    
    对不起,如果看起来我的回答很复杂的话

    我本想建议方法2,但是

    …因为您提到,当主对象/接口“IFile”时,必须在元数据的单个值更改时执行一些操作,并且元数据项没有“委托”、“事件”之类的内容,因此最好还是对元数据进行分组

    如果您的接口只存储数据,在添加或删除项时不执行任何操作,那么方法2将更实用

    在我看来,你自己也很复杂,直接跳入界面。我建议:

  • 制作一个完整的演示工作类MyClass
  • 使用相同的方法创建一个抽象超类,类MyClass:MySuperClass, 有一个工作演示
  • 以抽象超类为例,基于该超类设计一个接口
  • 有一种“更好的方法”,但“正确、完美、方法”在软件开发中并不存在,因为它太复杂了,无法用单一的方法来做事情。即使你选择了另一种方法,如果它有效,那么它也有效


    祝你好运;-)

    你为什么不使用属性?你能详细说明一下吗?在方法1)中,为了清晰起见,我只编写了单独的get set函数。谢谢你的回答。直到现在我才知道IDictionary,它看起来是一个不错的选择。其他方法的问题是,元数据没有适当的封装,整个集合是公开的,可以在不与包含对象交互的情况下进行操作。如果需要进行任何验证,那么在实现IFile的过程中就不能保留这种逻辑,因为元数据可以在任何地方修改。对于特定的值需要Get/Set方法,而不是整个元数据集合更好。
    public class JFile
    {
        ...
    
        protected Dictionary Metadata() { ... }
    
        ...
    
        // --> all this use "Dictionary" internally
        // --> but, do somthing to other "IFile" fields
    
        public String GetValue(String key) { ... }
        public void SetValue(String key, String value)  { ... }
        public Boolean Contains(String key)  { ... }
        public void Delete(String key)  { ... }
    }