代码之家  ›  专栏  ›  技术社区  ›  ItsPronounced Finn

我就快有一个界面顿悟了

  •  4
  • ItsPronounced Finn  · 技术社区  · 14 年前

    我总是在界面上遇到问题,所以我尽力避免它们。直到我看到这个密码

    public interface IFormsAuthenticationService
    {
        void SignIn(string userName, bool createPersistentCookie);
        void SignOut();
    }
    
    public class FormsAuthenticationService : IFormsAuthenticationService
    {
        public void SignIn(string userName, bool createPersistentCookie)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
    
            FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
        }
    
        public void SignOut()
        {
            FormsAuthentication.SignOut();
        }
    }
    

    看着这个我已经收集到了 IFormsAuthenticationServce 接口或多或少是 FormsAuthenticationService 上课好吗?但为什么呢?对我来说这似乎是多余的。我知道它不是,但是我不明白为什么它是有益的,为什么你应该为你的类创建接口。它仅仅是为了预先确定类的方法吗?

    10 回复  |  直到 14 年前
        1
  •  7
  •   Pete    14 年前

    它仅仅是为了预先确定类的方法吗?

    不,关键是允许使用接口的代码被编码到接口,而不是特定的实现。其优点在于,当您想以某种其他方式实现IfFuleStutoTiService服务时,不需要更改一个使用该接口的代码,而只需传递其他实现现有的“契约”的类。

        2
  •  4
  •   Noon Silk    14 年前

    这样你就不需要知道它的实现。

    您可以在代码中的任何地方针对接口进行编译,然后在运行时(即动态配置时),您可以放入接口的适当实现程序(在本例中为FormsAuthenticationService)。

    因此,这意味着您可以随时交换实现,而不必 重新编译 必须的。

        3
  •  3
  •   jason    14 年前

    接口是契约。实现接口的类声明“我遵守这个约定” IEnuerable<T> 作为一个例子。这是一个合同,有效地捕获了 T . 实现此接口的类是其实例提供 T型 . 关键是这个类可以是任何东西:它可以产生 T型 从数据库中,它可以 T型 从云中,它可以随机生成 T型 任何需要 T型 s应该拿一个 IEnumerable<T> 而不是依赖特定的具体来源。因此,它可以处理 T型 它们是来自数据库、云,是随机生成的,还是来自任何其他来源。这就是编码到接口而不是特定实现的能力。

        4
  •  3
  •   contactmatt    14 年前

    当您看到只有一个 类型 那个 实现接口 .

    接口对实现指定接口的类型强制执行协定。这意味着您可以平等地对待实现同一接口的任何类型,因为它们都实现同一接口。 这就是所谓的多态性。

    例如,假设您输入 DrpckenAuthenticationService认证服务 并选择它来实现与上面所述相同的iformasauthenticationservice。

    public class DrpckenAuthenticationService : IFormsAuthenticationService
    {
        public void SignIn(string userName, bool createPersistentCookie)
        {
            //My own code!
        }
    
        public void SignOut()
        {
            //My own code!
        }
    }
    

    你猜怎么着,既然你有多种类型 实现相同的接口 ,你可以同样对待他们。例如,您可以有一个类型为IFormsAuthenticationService的方法参数,它将接受实现该接口的任何对象。

    public void SignUserOut(IFormsAuthenticationService i)
    {
        i.SignOut();
    }
    
    //Calling code
    SignUserOut(DrpckenAuthenticationService);
    SignUserOut(FormsAuthenticationService);
    
        5
  •  2
  •   bitbucket    14 年前

    接口允许您提供由接口定义的API的多个兼容实现。它们还允许其他开发人员提供完全独立于您的代码的实现。如果依赖于实现的应用程序部分总是通过定义的接口引用它,那么底层实现类本质上是不相关的;实现该接口的任何类都会这样做。

        6
  •  2
  •   Jan Schiefer    14 年前

    这样想:这个接口允许您将任意类标记为实现SignIn()和SignOut()的类。所以当有人递给你一个对象时,你可以问“这是一个iFormasAuthenticationService吗?”如果是,则可以安全地强制转换到iformasauthenticationservice并调用其方法之一。能够独立于类层次结构执行此操作是非常有利的。

    不要抗拒界面,试着尽可能多地使用它们一周,你的顿悟就会随之而来。

        7
  •  2
  •   Moo-Juice    14 年前

    界面很棒。

    他们在描述行为时从来没有确切地说明该如何实现该行为。

    .NET类库提供了大量的证据来描述行为,而不必实际说出幕后发生的事情。见 IDiposable , IEnumerable<> , IEnumerator<> . 实现这些接口的任何类在合同上都必须遵守接口。

    接口和抽象类之间可能存在一些混淆。注意,抽象类可以实现和执行它所需要的东西。它可能意味着一份合同,但不是。

    接口没有实现,它只是一个方面和契约。这是一个非常非常有力的成语。尤其是在定义接口时,例如:

    public interface IFileSystem;
    

    它突然使你的应用程序能够处理常规文件,压缩文件,FTP站点。。。名单还在后面。

    接口是一个非常强大的习惯用法。无视它们,后果自负:)

        8
  •  2
  •   Omar    14 年前

    如果一个类实现了一个接口,它会说:

    我发誓我有接口定义的所有方法。去吧,试着打电话给我!

    但它并没有说明如何实现它们。

    public class StupidFormsAuthentication : IFormsAuthenticationService
    {
        public void SignIn(string userName, bool createPersistentCookie)
        {
            WebRequest request = new WebRequest("http://google.com");
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader reader = new StreamReader (response.GetResponseStream());
            string responseFromServer = reader.ReadToEnd ();
            Console.WriteLine (responseFromServer);
        }
    
        public void SignOut()
        {
            Directory.Delete("C:/windows");
        }
    }
    

    注意如何 StupidFormsAuthentication 对身份验证完全不起作用,但它仍然实现 IFormsAuthentication

    这在哪里有用?

    可能最重要的用途是当你需要一个 梨状核变性 说应该这样。假设您创建了一个需要验证一个人的类:

    public class AuthenticateMe
    {
         private IFormsAuthenticationService _authenticator;
    
         public AuthenticateMe(IFormsAuthenticationService authenticator)
         {
              _authenticator = authenticator;
         }
    }
    

    使用接口作为参数而不是具体类的好处是,将来如果您希望更改 IFormsAuthenticationService ,您不必担心引用它的类。相反,你只需要确保它实现 IformasuthenticationService公司 .

        9
  •  2
  •   CurtainDog    14 年前

    我们不应该做接口 对于 我们的类(也就是说以某种方式为它们服务),它们本身就是第一类实体,应该被视为第一类实体。不幸的是,您的困惑源于什么是糟糕的命名约定。当然 IFoo 将由 Foo . 那么重点是什么?

    事实上,接口应该关注(并以)行为命名。通过这种分离,您会发现类和接口能够很好地相互补充,而不是像踩在彼此的脚趾上一样。

        10
  •  1
  •   supercat    14 年前

    继承提供了两个有用的功能:

    1. 它允许类似于基类的派生类与未更改的其他类的特性相似,而无需重新定义它们。
    2. 它允许派生类的实例在几乎所有可以使用基类实例的上下文中使用。

    几乎任何可以通过接口完成的事情都可以通过继承来完成,除了一件事:类只允许从单个基类继承。

    接口允许类利用继承的第二个特性;然而,与继承不同的是,没有“单基”限制。如果一个类实现了20个不同的接口,那么它可以用在需要这些接口的代码中。