【问题标题】:.net Interface explanation.net接口说明
【发布时间】:2010-01-07 16:17:10
【问题描述】:

我知道 .Net 中的接口定义了接口和继承它的类之间的协定。刚刚完成了一个大量使用数据访问层接口的项目,这让我开始思考。 . .有什么大不了的?当我必须向 DAL 添加新方法时,我必须在接口中创建方法签名,并将其添加到继承接口的类中,当然还有将方法添加到 DAL,从而创建“额外工作”。接口有什么大不了的,我为什么要为自己创造额外的工作?

【问题讨论】:

标签: .net interface


【解决方案1】:

接口有什么大不了的?

一旦定义了合约,您就可以换出实现,而不必担心破坏其余代码。

考虑在 .NET 中使用 List<T> 的代码性能不佳的情况。如果您使用List<T> 的硬实现,那么您很有可能会通过更改实现来破坏更多代码。

如果您使用的是IList<T>IEnumerable<T>,您可以将List<T> 替换为LinkedList<T>(或任何实现您选择的界面的东西)并在一个地方解决问题,而不必触摸您的所有代码。

最后...是关于Polymorphism

【讨论】:

    【解决方案2】:

    IMO 最重要的是,接口不像类那样绑定到特定的继承层次结构,因此它们比实现抽象接口的类更灵活。通过使用接口而不是具体的类,您将拥有一个更松散耦合的系统。更改实现很容易:只需提供实现所需接口的任何其他类。

    【讨论】:

      【解决方案3】:

      如果您有两个类,两个具有不同实现的不同数据访问层类(可能是 SQL Server 和 CouchDB),那么拥有一个标准接口(它们都实现)意味着您拥有与这些类交互的标准方式.

      您将能够“热交换”不同的数据类,而不必知道具体的底层实现。

      【讨论】:

        【解决方案4】:

        使用接口的一个原因是在类之间创建松散耦合。

        例如,如果您在类构造函数中传递一个接口,而不是实际的类,您将允许更松散的耦合。因为任何人都可以从接口继承并实现自己的实现。

        【讨论】:

          【解决方案5】:
                  foreach (object obj in myArray)
                  {
                      // distroy all IDisposable objects
                      if (obj is IDisposable)
                          (obj as IDisposable).Dispose();
          
                      // ends initialization of all ISupportInitialize objects
                      else if (obj is ISupportInitialize)
                          (obj as ISupportInitialize).EndInit();
                  }
          

          因此,如果一些不同的对象实现了相同的接口,则该接口保证每个对象都有一些通用方法,在该接口中进行了描述。

          这在收集对象时非常有用。你知道所有的动物s(包括人类)都可以。所以你知道,如果车里有动物,它们每个都可以吃,人类老鼠斑马...

          所以接口 IEatable :)...

          【讨论】:

            【解决方案6】:

            当我在学校的时候,我没有得到接口甚至迭代器的美感,因为我们试图解决的问题可以在不使用抽象的情况下用 1/2 的代码量完成。

            一般来说,软件模式源于行业的实际需求。我想接口在某些时候几乎被认为是一种模式。

            由于时间限制,学校项目可以教给您的内容有限。

            【讨论】:

              【解决方案7】:

              如果您要更改数据的存储方式,您只需要创建一个实现 DAL 接口的新类,您的应用程序就可以立即使用它。您无需查找应用程序中的所有使用实例并将旧类替换为新类。

              例如,您还可以使用 IoC(在 Castle Windsor 或其他库的帮助下)通过配置插入特定的数据访问风格,而无需重新编译您的应用程序。

              【讨论】:

                【解决方案8】:

                在您的示例中,您只有一个实现接口的类,您没有看到好处。如果您有 10 个类都实现了该接口,您会立即看到优势。

                如果您有一个 IFoo 集合,您可以将任何实现 IFoo 的类粘贴到该集合中,并对每个对象调用相同的 Bar() 方法。 Bar() 的实现在实现它的每个类中可能会有很大的不同。

                【讨论】:

                  【解决方案9】:

                  简单来说,接口用于在两个组件之间提供一个干净的分离点。与其将组件设计为针对单一类型(例如 List<T>),不如将其设计为针对接口 (IList<T>) 并能够与实现该接口的任何对象一起使用。

                  当您开始使用依赖注入和模拟测试的想法时,这种分离非常有用。

                  【讨论】:

                    【解决方案10】:

                    将接口视为对象(或服务)与该服务的用户之间的合同的更好方法。在你的 DAL 问题中,接口的真正价值是能够用同样实现接口的不同实现替换实现接口的类。所以说你的 DAL 实现是特定于 SQL Server 的,但现在你需要 MySQL 支持。您编写另一个与 MySQL 对话的接口的 impl,将其插入,使用 DAL 的代码不需要更改。优势在于客户端代码,而不是实现。

                    它在测试中也很有帮助,允许您插入假的或模拟的接口实现,在执行测试时模拟所需的行为。

                    【讨论】:

                    • 说的有道理,不过是我继承的一个项目,每个DAL方法都继承了这个接口,好像真的没有加到代码里
                    【解决方案11】:

                    我可以通过使用接口使我的代码更易于测试。

                    如果我有一个 ManagerClass

                    public class PersonManager
                    {
                      public PersonManager(IPersonRepository repository)
                      {
                        this.Repository = repository;
                      }
                      private IPersonRepository Repository{get;set;}
                    
                      public Person ChangeUsername(string username)
                      {
                        Person person = this.Repository.GetByUsername(username);
                        person.Username = username;
                        this.Repository.Save(person);
                        return person;
                      }
                    }
                    

                    发布代码将使用将调用数据库的存储库对象,但对于我的单元测试,我想隔离对数据库的依赖,以便我可以创建一个实现我的接口的模拟存储库:

                    public class MockPersonRepository : IPersonRepository
                    {
                       public Person GetByUsername(string username)
                       {
                          return new Person();
                       }
                       public void Save()
                       {}
                    }
                    

                    当我编写单元测试时,我可以通过模拟:

                    [Test]
                    public void ChangeUserName_NewUsername_ExpectUpdateUsername()
                    {
                      //Arrange
                      var manager = new PersonManager(new MockPersonManager());
                    
                      //Act
                      Person person = manager.ChangeUsername("bob");
                    
                      //Assert
                      Assert(AreEqual("bob", person.Username);
                    }
                    

                    我现在有经理来测试我的 ChangeUsername 方法是否在不与数据库对话的情况下更新了用户名

                    【讨论】:

                      猜你喜欢
                      • 2015-03-17
                      • 2018-02-01
                      • 2011-01-28
                      • 2015-03-16
                      • 2012-10-10
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-03-19
                      • 2011-01-29
                      相关资源
                      最近更新 更多