使用接口variables
我仍然试图更好地理解接口。 我知道他们是什么以及如何在课堂上实施他们。
我不明白的是当你创build一个你的接口types的variables:
IMyInterface somevariable;
你为什么要这样做? 我不明白IMyInterface如何像类一样使用…例如调用方法,所以:
somevariable.CallSomeMethod();
为什么你会使用IMyInterfacevariables来做到这一点?
您不是创build接口的实例 – 您正在创build一个实现接口的实例。
接口的要点是它保证了实现它的东西将提供在其中声明的方法。
所以,现在,用你的例子,你可以有:
MyNiftyClass : IMyInterface { public void CallSomeMethod() { //Do something nifty } } MyOddClass : IMyInterface { public void CallSomeMethod() { //Do something odd } }
现在你有:
IMyInterface nifty = new MyNiftyClass() IMyInterface odd = new MyOddClass()
调用CallSomeMethod方法现在可以完成一些奇妙的事情或者奇怪的事情,当你使用IMyInterface作为types传递时,这变得特别有用。
public void ThisMethodShowsHowItWorks(IMyInterface someObject) { someObject.CallSomeMethod(); }
现在,根据你是否调用一个漂亮的或奇怪的类的上述方法,你会得到不同的行为。
public void AnotherClass() { IMyInterface nifty = new MyNiftyClass() IMyInterface odd = new MyOddClass() // Pass in the nifty class to do something nifty this.ThisMethodShowsHowItWorks(nifty); // Pass in the odd class to do something odd this.ThisMethodShowsHowItWorks(odd); }
编辑
这解决了我认为你想要的问题是 – 为什么你会声明一个variables是一个接口types?
那就是为什么使用:
IMyInterface foo = new MyConcreteClass();
优先于:
MyConcreteClass foo = new MyConcreteClass();
希望你明白为什么在声明一个方法签名的时候会使用这个接口,但是这留下了关于本地作用域variables的问题:
public void AMethod() { // Why use this? IMyInterface foo = new MyConcreteClass(); // Why not use this? MyConcreteClass bar = new MyConcreteClass(); }
通常没有技术上的理由为什么接口是首选。 我通常使用的界面,因为:
- 我通常注入依赖关系,因此需要多态性
- 使用界面清楚地表明我的意图只使用界面的成员
技术上需要接口的地方就是使用多态的地方,例如使用工厂或使用dependency injection(如上所述)创buildvariables。
借用itowlson的一个例子,使用具体的声明你不能这样做:
public void AMethod(string input) { IMyInterface foo; if (input == "nifty") { foo = new MyNiftyClass(); } else { foo = new MyOddClass(); } foo.CallSomeMethod(); }
因为这:
public void ReadItemsList(List<string> items); public void ReadItemsArray(string[] items);
可以变成这样:
public void ReadItems(IEnumerable<string> items);
编辑
像这样想:
你必须能够做到这一点。
而不是:
你必须是这个。
本质上这是方法和它的调用者之间的契约。
可以说你有class船,汽车,卡车,飞机。
这些都共享一个共同的方法TakeMeThere(string目的地)
你将有一个接口:
public interface ITransportation { public void TakeMeThere(string destination); }
那么你的class级:
public class Boat : ITransportation { public void TakeMeThere(string destination) // From ITransportation { Console.WriteLine("Going to " + destination); } }
你在这里说的是,我的class级船将做所有的传送也告诉我。
然后,当你想为运输公司制作软件。 你可以有一个方法
Void ProvideServiceForClient(ITransportation transportationMethod, string whereTheyWantToGo) { transportationMethod.TakeMeThere(whereTheyWantToGo); // Cause ITransportation has this method }
所以,他们想要什么types的交通并不重要,因为我们知道它可以TakeMeThere
使用接口variables是允许编写处理程序方法的唯一方法,它可以接受来自具有不同基类的对象的数据。
这是任何人都会明白的。
我处于相同的位置,花了几天的时间才弄清楚为什么我们不得不使用接口variables。
IDepartments rep = new DepartmentsImpl();
为什么不
DepartmentsImpl rep = new DepartmentsImpl();
想象一下,如果一个类实现了两个包含具有相同签名的成员的接口,那么在该类上实现该成员将导致这两个接口都将该成员用作其实现。
class Test { static void Main() { SampleClass sc = new SampleClass(); IControl ctrl = (IControl)sc; ISurface srfc = (ISurface)sc; // The following lines all call the same method. sc.Paint(); ctrl.Paint(); srfc.Paint(); }
}
interface IControl { void Paint(); } interface ISurface { void Paint(); } class SampleClass : IControl, ISurface { // Both ISurface.Paint and IControl.Paint call this method. public void Paint() { Console.WriteLine("Paint method in SampleClass"); }
}
// Output: // Paint method in SampleClass // Paint method in SampleClass // Paint method in SampleClass
但是,如果两个接口成员不执行相同的function,则可能导致一个或两个接口的错误实现。
public class SampleClass : IControl, ISurface { void IControl.Paint() { System.Console.WriteLine("IControl.Paint"); } void ISurface.Paint() { System.Console.WriteLine("ISurface.Paint"); } }
类成员IControl.Paint只能通过IControl接口使用,ISurface.Paint只能通过ISurface使用。 这两种方法的实现是分开的,都不能直接在类上使用。 例如:
IControl c = new SampleClass(); ISurface s = new SampleClass(); s.Paint();
如果我错了,请纠正我,因为我仍然在学习这个接口概念。
这不是特定于C#,所以我build议移动到其他国旗。 对于你的问题,我们select接口的主要原因是在两个组件之间提供协议(可以是dll,jar或其他任何组件)。 请参阅下面
public class TestClass { static void Main() { IMyInterface ob1, obj2; ob1 = getIMyInterfaceObj(); obj2 = getIMyInterfaceObj(); Console.WriteLine(ob1.CallSomeMethod()); Console.WriteLine(obj2.CallSomeMethod()); Console.ReadLine(); } private static bool isfirstTime = true; private static IMyInterface getIMyInterfaceObj() { if (isfirstTime) { isfirstTime = false; return new ImplementingClass1(); } else { return new ImplementingClass2(); } } } public class ImplementingClass1 : IMyInterface { public ImplementingClass1() { } #region IMyInterface Members public bool CallSomeMethod() { return true; } #endregion } public class ImplementingClass2 : IMyInterface { public ImplementingClass2() { } #region IMyInterface Members public bool CallSomeMethod() { return false; } #endregion } public interface IMyInterface { bool CallSomeMethod(); }
这里的主要方法并不知道类仍然可以使用接口获得不同的行为。
使用一个接口,所以你不必担心什么类实现接口。 一个有用的例子是当你有一个工厂方法返回一个具体的实现,这个实现可能根据你所运行的环境而有所不同。它还允许APIdevise者定义API,同时允许第三方实现API任何他们认为合适的方式。 Sun使用Java的encryptionAPI来执行此操作。
public interface Foo { } public class FooFactory { public static Foo getInstance() { if(os == 'Windows') return new WinFoo(); else if(os == 'OS X') return new MacFoo(); else return new GenricFoo(); } }
你使用工厂的代码只需要知道Foo,而不是任何具体的实现。
接口的目的是定义几个对象之间的契约,而不依赖于具体的实现。
所以当你有一个Intrace ISomething
和一个特定的实现时,你通常会使用它
class Something : ISomething
所以当你实例化一个契约时,接口variables会被使用:
ISomething myObj = new Something(); myObj.SomeFunc();
你也应该阅读接口C#
更新:
我将通过一个(现实生活)的例子来解释为variables使用接口而不是类本身的逻辑:
我有一个通用的存储器接口:
Interface IRepository { void Create(); void Update(); }
我有2个独立的实现:
class RepositoryFile : interface IRepository {} class RepositoryDB : interface IRepository {}
每个类都有一个完全不同的内部实现。
现在我有另一个对象,一个logging器,使用一个已经instansiated存储库来做他的写作。 这个对象并不关心Repository是如何实现的,所以他只是实现了:
void WriteLog(string Log, IRepository oRep);
顺便说一句,这也可以通过使用标准的类inheritance来实现。 但是使用接口和类inheritance的区别是另外一个讨论。
有关抽象类和接口之间的区别的更多细节讨论,请看这里 。
比方说,你有两个class: Book
和Newspaper
。 你可以阅读其中每一个,但这两个从一个普通的超类inheritance是没有意义的。 所以他们都会实现IReadable
接口:
public interface IReadable { public void Read(); }
现在说,你正在写一个应用程序,将阅读用户的书籍和报纸。 用户可以从列表中select一本书或报纸,并将该项目读取给用户。
在你的应用程序读取给用户的方法将把这Book
或Newspaper
作为参数。 这可能看起来像这样的代码:
public static void ReadItem(IReadable item) { item.Read(); }
由于该参数是一个IReadable
,我们知道该对象具有Read()
方法,因此我们称之为将其读取给用户。 无论这是一Book
, Newspaper
还是其他实现IReadable
其他内容都IReadable
。 各个类通过实现Read()
方法来精确地实现每个项目的Read()
方式,因为对于不同的类,它们很可能是不同的。
Book
的Read()
可能如下所示:
public void Read() { this.Open(); this.TurnToPage(1); while(!this.AtLastPage) { ReadText(this.CurrentPage.Text); this.TurnPage(); } this.Close(); }
Newspaper
的Read()
可能会有点不同:
public void Read() { while(!this.OnBackPage) { foreach(Article article in this.CurrentPage.Articles) { ReadText(article.Text); } } }
重点是,一个接口types的variables包含的对象保证有一组特定的方法,即使这个对象的可能的类没有以任何其他方式相关。 这使您可以编写适用于各种可以在其上执行常用操作的类的代码。
不,这是不可能的。 devise师没有提供一个方法。 当然,这也是常识。 因为接口仅包含抽象方法,而抽象方法没有实现代码的主体,所以我们不能创build一个对象。
假设即使允许,有什么用。 用对象调用抽象方法不会产生任何目的,因为没有输出。 没有function来抽象方法。 那么,Javadevise和编码中接口的用法是什么? 它们可以用作原型,从而可以轻松开发新课程。 它们像其他类的模板一样工作,像其他类一样实现接口,就像蓝图一样构build一个build筑物。
我相信每个人都在回答使用接口的多态原因,David Hall部分地涉及到了为什么要将其作为接口引用而不是实际的对象名称。 当然,限于接口成员等是有益的,但另一个答案是dependency injection/实例化。
当您devise应用程序时,如果使用dependency injection,则通常更清洁,更易于pipe理,并且更灵活。 如果你从来没有这样做过,那么你会感到倒退,但是当你开始回溯时,你会希望你有。
dependency injection通常是通过允许类实例化和控制依赖关系来实现的,而你只需要依靠你所需要的对象的接口。
例:
先将应用程序分层。 第1层逻辑,第2层接口,第3层dependency injection。 (每个人都有自己的方式,这只是表演)。
在逻辑层中,您可以引用接口和依赖层,然后最终创build仅基于异物接口的逻辑。
开始了:
public IEmployee GetEmployee(string id) { IEmployee emp = di.GetInstance<List<IEmployee>>().Where(e => e.Id == id).FirstOrDefault(); emp?.LastAccessTimeStamp = DateTime.Now; return emp; }
注意上面我们如何使用di.GetInstance从我们的依赖中获取一个对象。 我们在该层的代码永远不会知道或关心Employee对象。 事实上,如果它改变了其他代码,它将永远不会影响我们在这里。 如果IEmployee的接口发生变化,那么我们可能需要更改代码。
问题是,IEmployee emp =永远不知道实际的对象是什么,但知道接口以及如何使用它。 考虑到这一点,当你想使用一个接口而不是一个对象,因为我们永远不知道或有权访问该对象。
这是总结..希望它可以帮助。
这是面向对象编程中的一个基本概念 – 多态。 ( 维基百科 )
简单的答案是,通过使用类A中的接口,可以给A类任何IMyInterface
。
这也是一种松耦合的forms( 维基百科 ) – 在这里你有很多类,但是它们并不相互依赖 – 只是依赖于它们提供的一组属性和方法(接口)的抽象概念。