How will I know when to create an interface?

2020-01-23 02:32发布

问题:

I'm at a point in my development learning where I feel like I must learn more about interfaces.

I frequently read about them but it just seems like I cannot grasp them.

I've read examples like: Animal base class, with IAnimal interface for things like 'Walk', 'Run', 'GetLegs', etc - but I've never been working on something and felt like "Hey I should use an interface here!"

What am I missing? Why is it such a hard concept for me to grasp! I am just intimidated by the fact that I might not ever realize a concrete need for one - mostly due to some missing aspect of understanding them! It makes me feel like I'm missing something up top in terms of being a developer! If anyone has had an experience like this and had a breakthrough I would appreciate some tips on how to understand this concept. Thank you.

回答1:

it solves this concrete problem:

you have a, b, c, d of 4 different types. all over your code you have something like:

a.Process();
b.Process();
c.Process();
d.Process();

why not have them implement IProcessable, and then do

List<IProcessable> list;

foreach(IProcessable p in list)
    p.Process();

this will scale much better when you add, say, 50 types of classes that all do the same thing.


Another concrete problem:

Have you ever taken a look at System.Linq.Enumerable? It defines a ton of extension methods that operate on any type that implements IEnumerable. Because anything that implements IEnumerable basically says "I support iteration in a unordered foreach-type pattern", you can define complex behaviors (Count, Max, Where, Select, etc.) for any enumerable type.



回答2:

I like Jimmy's answer a lot, but I feel I need to add something to it. The key to the whole thing is the "able" in IProcessable . It indicates a capability (or property, but meaning "intrinsic quality", not in the sense of C# properties) of the object that implements the interface. IAnimal is probably not a good example for an interface, but IWalkable might be a good interface to have if your system has many things that can walk. You might have classes derived from Animal such as Dog, Cow, Fish, Snake. The first two would probably implement IWalkable, the latter two don't walk, so they wouldn't. Now you ask "why not just have another superclass, WalkingAnimal, that Dog and Cow derive from?". The answer is when you have something completely outside the inheritance tree that also can walk, such as a robot. Robot would implement IWalkable, but probably wouldn't derive from Animal. If you want a list of things that can walk, you type it as IWalkable and you can put all walking animals plus robots in the list.

Now replace IWalkable with something more software-y like IPersistable, and the analogy becomes much closer to what you'd see in a real program.



回答3:

Use interfaces when implementations of the same functionality will differ.

Use a abstract/base classes when you need to share a common concrete implementation.



回答4:

Think of an interface like a Contract. It's a way to say, "These classes should follow these set of rules."

So in the IAnimal example, it is a way to say, "I MUST be able to call Run, Walk, etc. on classes which implement IAnimal."

Why is this useful? You may want to build a function which relies on the fact that you must be able to call Run and Walk, for example, on the object. You could have the following:

public void RunThenWalk(Monkey m) {
    m.Run();
    m.Walk();
}

public void RunThenWalk(Dog d) {
    d.Run();
    d.Walk();
}

... and repeat that for all objects which you know can run and walk. However, with your IAnimal interface, you can define the function once as follows:

public void RunThenWalk(IAnimal a) {
    a.Run();
    a.Walk();
}

By programming against the interface, you are essentially trusting the classes to implement the intent of the interface. So in our example, the thought is "I don't care how they Run and Walk, so long as they Run and Walk. My RunThenWalk will be valid as long as they fulfill that agreement. It functions perfectly well without knowing anything else about the class."

There is also a good discussion in this related question.



回答5:

Don't worry so much. Lots of developers, will rarely need to write an interface. You'll frequently use interfaces available within the .NET framework, but if you don't feel the need to write one anytime soon there's nothing surprising about that.

The example I always give to someone is if you have a Sailboat class and a Viper class. They inherit the Boat class and the Car class respectively. Now say that you need to loop through all these objects and call their Drive() method. While you could write some code like the following:

if(myObject is Boat)
    ((Boat)myObject).Drive()
else
    if (myObject is Car)
        ((Car)myObject).Drive()

It would be much much simpler to write:

((IDrivable)myObject).Drive()


回答6:

Jimmy has it right, when you want to be able to use a single variable for multiple types, but all of those types implement the same method via an interface declaration. Then you can call them main method on the interface typed variable.

There's a second reason to use interfaces, however. When the project architect is a different person than the implementation coder, or there are several implementation coders and one project manager. The person in charge can write a whole bunch of interfaces and see that the system interoperates, and then leave it to the developers to fill in the interfaces with implementation classes. This is the best way to ensure multiple people write compatible classes, and they can do it in parallel.



回答7:

I like army analogy.

Sergeant doesn't care if You are a software developer, musician or lawyer.
You are treated as soldier.

It's easier for sergeant not to bother with specific details of persons he is working with,
treat everyone as soldier abstractions (...and punish them when they fail to act like ones).

Ability for persons to act like soldiers is called polymorphism.

Interfaces are software constructions that helps to achieve polymorphism.

Need to abstract details in order to achieve simplicity is answer to Your question.

Polymorphism, which etymologically means "many forms," is the ability to treat an object of any subclass of a base class as if it were an object of the base class. A base class has, therefore, many forms: the base class itself, and any of its subclasses.

(..) This makes your code easier for you to write and easier for others to understand. It also makes your code extensible, because other subclasses could be added later to the family of types, and objects of those new subclasses would also work with the existing code.



回答8:

In my experience the driving force to create interfaces didn't occur until I start doing unit testing with a mocking framework. It became abundantly clear that using interfaces was going to make mocking much easier (since the framework depended on the methods being virtual). Once I started I saw the value of abstracting away the interface to my class from the implementation. Even if I don't create an actual interface, I try now to make my methods virtual (providing an implicit interface that can be overridden).

There are lots of other reasons that I've found to reinforce the good practice of refactoring to interfaces, but the unit testing/mocking thing was what provided the intial "aha moment" of practical experience.

EDIT: To clarify, with unit testing and mocking I always have two implementations -- the real, concrete implementation and an alternate mock implementation used in testing. Once you have two implementations, the value of the interface becomes obvious -- deal with it in terms of the interface so you can replace the implementation at any time. In this case I'm replacing it with a mock interface. I know that I can do this without an actual interface if my class is constructed properly, but using an actual interface reinforces this and makes it cleaner (clearer to the reader). Without this impetus, I don't think I would have appreciated the value of interfaces since most of my classes only, ever have a single concrete implementation.



回答9:

Some non-programming examples that might help you see the appropriate uses of interfaces in programming.

There's an interface between electrical devices and the electricity network - it's the set of conventions about the shape of the plugs and sockets and the voltages/currents across them. If you want to implement a new electrical device, as long as your plug follows the rules it will be able to get services from the network. This makes extensibility very easy and removes or lowers the costs of coordination: you don't have to notify the electricity provider about how your new device works and come to a separate agreement about how to plug your new device into the network.

Countries have standard rail gauges. This allows a division of labour between engineering companies who put down rails and engineering companies who build trains to run on those rails, and it makes it possible for rail companies to replace and upgrade trains without rearchitecting the whole system.

The service a business presents to a client can be described as an interface: a well defined interface emphasises the service and hides the means. When you put a letter in a mailbox, you expect the postal system to deliver the letter within a given time but you have no expectations about how the letter is delivered: you don't need to know, and the postal service has the flexibility to choose the means of delivery that best meets the requirements and current circumstances. An exception to this is the ability of customers to choose airmail - that's not the kind of interface a modern computer programmer would have designed, since it reveals too much of the implementation.

Examples from nature: I'm not too keen on the eats(), makesSound(), moves(), etc examples. They do describe behaviour, which is correct, but they don't describe interactions and how they're enabled. The obvious examples of interfaces that enable interactions in nature are to do with reproduction, for example a flower provides a certain interface to a bee so that pollination can take place.



回答10:

It's entirely possible to go your whole life as a .net developer and never write your own interfaces. After all, we survived fine without them for decades and our languages were still Turing-complete.

I can't tell you why you need interfaces, but I can give you a list of where we use them in our current project:

  1. In our plug-in model, we load plug-ins by interface and provide that interface to plug-in writers to conform to.

  2. In our intermachine messaging system, the message classes all implement a specific interface and are "unwrapped" using the interface.

  3. Our configuration management system defines an interface used to set and retrieve configuration settings.

  4. We have one interface that we use to avoid a nasty circular reference problem. (Don't do this if you don't have to.)

I guess if there's a rule, it's to use interfaces when you want to group several classes within an is-a relationship, but you don't want to provide any implementation in the base class.



回答11:

A code example (combination of Andrew's with an extra of mine at what-is-the-purpose-of-interfaces), that also makes a case on why interface instead of an abstract class on languages with no support for multiple inheritance (c# and java):

interface ILogger
{
    void Log();
}
class FileLogger : ILogger
{
    public void Log() { }
}
class DataBaseLogger : ILogger
{
    public void Log() { }
}
public class MySpecialLogger : SpecialLoggerBase, ILogger
{
    public void Log() { }
}

Notice that the FileLogger and DataBaseLogger doesn't need the interface (could be a Logger abstract base class). But consider you are required to use a third party logger that forces you to use a base class (lets say it exposes protected methods you Need to use). As the language doesn't support multiple inheritance you won't be able to use the abstract base class approach.

Bottom line is: use an interface when possible to get extra flexibility on your code. Your implementation is less tied, so it accomodates better for change.



回答12:

I've used interfaces now and then and here's my latest usage (names have been generalized):

I have a bunch of custom controls on a WinForm that need to save data to my business object. One approach is to call each control separately:

myBusinessObject.Save(controlA.Data);
myBusinessObject.Save(controlB.Data);
myBusinessObject.Save(controlC.Data);

The problem with this implementation is that any time I add a control I have to go into my "Save Data" method and add the new control.

I changed my controls to implement an ISaveable interface that has a method SaveToBusinessObject(...) so now my "Save Data" method just iterates through the controls and if it finds one that is ISaveable, it calls SaveToBusinessObject. So now when a new control is needed, all someone has to do is implement ISaveable in that object (and never touch another class).

foreach(Control c in Controls)
{
  ISaveable s = c as ISaveable;

  if( s != null )
      s.SaveToBusinessObject(myBusinessObject);
}

The oftentimes unrealized benefit to interfaces is that you localize modifications. Once defined, you'll rarely change the overall flow of an application but you will often make changes on the detail-level. When you keep the details in specific objects, a change in ProcessA will not affect a change in ProcessB. (Base classes also give you this benefit.)

EDIT: Another benefit is specificity in actions. Like in my example, all I want to do is save the data; I don't care what type of control it is or if it can do anything else -- I just want to know if I can save the data in the control. It makes my save code pretty clear -- there are no checks to see if it's text, numeric, boolean or whatever because the custom control handles all of that.



回答13:

You should define an interface once you need to force a behaviour for your class.

An Animal's behaviour may involve Walking, Eating, Running, etc. Therefore, you define them as interfaces.

Another practical example is the ActionListener (or Runnable) interface. You would implement them when you need to keep track of a particular event. Therefore, you need to provide the implementation for the actionPerformed(Event e) method in your class (or subclass). Similarly, for the Runnable interface, you provide the implementation for the public void run() method.

Also, you can have these interfaces implemented by any number of classes.

Another instance where Interfaces are used (in Java) is to implement the multiple inheritance offered in C++.



回答14:

Assume you want to want to model annoyances which might happen when you try to go to sleep.

Model before interfaces

class Mosquito {
    void flyAroundYourHead(){}
}

class Neighbour{
    void startScreaming(){}
}

class LampJustOutsideYourWindow(){
    void shineJustThroughYourWindow() {}
}

As you clearly see many 'things' can be annoying when you try to sleep.

Usage of classes without interfaces

But when it comes to using these classes we have a problem. They have nothing in common. You have to call each method separately.

class TestAnnoyingThings{
    void testAnnoyingThinks(Mosquito mosquito, Neighbour neighbour, LampJustOutsideYourWindow lamp){
         if(mosquito != null){
             mosquito.flyAroundYourHead();
         }
         if(neighbour!= null){
             neighbour.startScreaming();
         }
         if(lamp!= null){
             lamp.shineJustThroughYourWindow();
         }
    }
}

Model with interfaces

To overcome this probem we can introduce an iterface

interface Annoying{
   public void annoy();

}

And implement it inside classes

class Mosquito implements Annoying {
    void flyAroundYourHead(){}

    void annoy(){
        flyAroundYourHead();
    }
}

class Neighbour implements Annoying{
    void startScreaming(){}

    void annoy(){
        startScreaming();
    }
}

class LampJustOutsideYourWindow implements Annoying{
    void shineJustThroughYourWindow() {}

    void annoy(){
        shineJustThroughYourWindow();
    }
}

Usage with interfaces

Which will make usage of these classes much easier

class TestAnnoyingThings{
    void testAnnoyingThinks(Annoying annoying){
        annoying.annoy();
    }
}


回答15:

The easiest example to give is something like Payment Processors.(Paypal, PDS etc).

Say you create an interface IPaymentProcessor that has ProcessACH and ProcessCreditCard methods.

You can now implement a concrete Paypal implementation. Making those methods call PayPal specific functions.

If you decide later you need to switch to another provider, you can. Just create another concrete implementation for the new provider. Since all you are tied to is your interface(contract), you can swap out which one your application uses without changing the code that consumes it.



回答16:

It also allows you to perform Mock unit testing (.Net). If your class uses an interface, you can mock the object in your unit testing and easily test logic (without actually hitting the database, or web service, etc).

http://www.nmock.org/



回答17:

If you browse the .NET Framework assemblies and drill down into the base classes for any of the standard objects, you will notice many interfaces (members named as ISomeName).

Interfaces are basically for implementing frameworks, large or small. I felt the same way about interfaces until I wanted to write a framework of my own. I also found that understanding interfaces helped me learn frameworks much more rapidly. The moment that you want to write a more elegant solution for just about anything, you will find that an interface makes a lot of sense. It's like a method of letting a class put on the appropriate clothes for the job. More importantly, interfaces allow systems to become much more self-documenting, because complex objects become less complex when the class implements interfaces, which helps to categorize its functionality.

Classes implement interfaces when they want to be able to participate in a framework explicitly or implicitly. For example, IDisposable is a common interface that provides method signature for the popular and useful Dispose() method. In a framework, all that you or another developer needs to know about a class is that if it implements IDisposable, then you know that ((IDisposable)myObject).Dispose() is available to be called for cleanup purposes.

CLASSIC EXAMPLE: without implementing the IDisposable interface, you cannot use the "using( )" keyword construct in C#, because it requires that any object specified as a parameter can be implicitly cast to IDisposable.

COMPLEX EXAMPLE: A more complex example would be the System.ComponentModel.Component class. This class implements both IDisposable and IComponent. Most, if not all, .NET objects that have a visual designer associated with them implement IComponent so that the IDE will be able to interact with the component.

CONCLUSION: As you become more familiar with the .NET Framework, the first thing you will do when encountering a new class in the Object Browser or within the .NET Reflector (free) tool (http://www.red-gate.com/products/reflector/) is to check to see which class it inherits from and also the interfaces that it implements. .NET Reflector is even better than the Object Browser because it lets you see the Derived classes as well. That allows you to learn about all objects that derive from a particular class, thereby potentially learning about framework functionality that you did not know existed. This is particularly significant when updated or new namespaces are added to the .NET Framework.



回答18:

Consider you are making a first person shooting game. The player has multiple guns to choose from.

We can have an interface Gun which defines a function shoot().

We need different subclasses of Gun class namely ShotGun Sniper and so on.

ShotGun implements Gun{
    public void shoot(){
       \\shotgun implementation of shoot.
    } 
}

Sniper implements Gun{
    public void shoot(){
       \\sniper implementation of shoot.
    } 
}

Shooter Class

The shooter has all the guns in his Armour. Lets create a List to represent it.

List<Gun> listOfGuns = new ArrayList<Gun>();

The shooter cycles through his guns,as and when needed, using the function switchGun()

public void switchGun(){
    //code to cycle through the guns from the list of guns.
    currentGun = //the next gun in the list.
}

We can set the current Gun , using the above function and simply call shoot() function, when fire() is called.

public void fire(){
    currentGun.shoot();
}

The behavior of the shoot function will vary according to different implementations of the Gun interface.

Conclusion

Create an interface, when a class function is dependent on a function from another class, which is subjected to change its behavior, based on instance(object) of the class implemented.

for e.g. fire() function from Shooter class expects guns(Sniper, ShotGun) to implement the shoot() function. So if we switch the gun and fire.

shooter.switchGun();
shooter.fire();

We have changed the behaviour of fire() function.



回答19:

To expand on what Larsenal has said. An Interface is a contract that all implementing classes must follow. Because of this, you can use a technique called programming to the contract. This allows your software to become implementation independent.



回答20:

Interfaces are generally used when you want to define a behavior that objects can exhibit.

A good example of this in the .NET world is the IDisposable interface, which is used on any Microsoft classes that use system resources that must be manually released. It requires that the class implementing it have a Dispose() method.

(The Dispose() method is also called by the using language construct for VB.NET and C#, which only works on IDisposables)

Keep in mind that you can check if an object implements a specific interface by using constructs such as TypeOf ... Is (VB.NET), is (C#), instanceof (Java), etc...



回答21:

As several people have probably already answered, interfaces can be used to enforce certain behaviors between classes that will not implement those behaviors the same way. So by implementing an interface you are saying that your class has the behavior of the interface. The IAnimal interface would not be a typical interface because Dog, Cat, Bird, etc. classes are types of animals, and should probably extend it, which is a case of inheritance. Instead, an interface would be more like animal behavior in this case, such as IRunnable, IFlyable, ITrainable, etc.

Interfaces are good for many things, one of the key things is pluggability. For example, declaring a method that has a List parameter will allow for anything that implements the List interface to be passed in, allowing the developer to remove and plug in a different list at a later time without having to rewrite a ton of code.

It is possible you'll never use interfaces, but if you're designing a project from scratch, especially a framework of some sort, you'll probably want to get familiar with them.

I would recommend reading the chapter on interfaces in Java Design by Coad, Mayfield, and Kern. They explain it a little better than the average introductory text. If you don't use Java, you can just read the beginning of the chapter, which is just mainly concepts.



回答22:

As any programming technics that add flexibility to your system, interfaces also add some level of complexity. They are often great and you could use it everywhere (you can create an interface for all of your classes) -- but doing so, you would create a more complex system that would be harder to maintain.

There is a trade-off here, as usual : flexibility over maintainability. Which one is more important ? There is no answers - it depends on the project. But just remember that every softwares will have to be maintained...

So my advice : don't use interfaces until you really need them. (With Visual Studio, you can extract an interface from an existing class in 2 seconds - so don't hurry.)

Having said that, when do you need to create an interface ?

I do it when I'm refactoring a method that suddenly need to process two or more similar classes. I then create an interface, assign this interface to the two (or more) similar classes and I change the method parameter type (replace the class type with the interface type).

And it works :o)

One exception : when I when to mock objects, interface are much more easier to use. So I often create interface just for this.

PS : when I write "interface", I mean : "interface of any base class", including pure interface classes. Note that abstract classes are often a better bet then pure interfaces since you can add logic to them.

Regards, Sylvain.



回答23:

Interfaces will become evident when you become a library developer (someone who codes for other coders). Most of us begin as application developers, where we use existing APIs and programming libraries.

Along the same lines that Interfaces are a contract, nobody mentioned yet that Interfaces are a great way to make some parts of your code stable. That's especially useful when it's a team project (or when you're developing code used by other developers). So, here's a concrete scenario for you:

When you are developing code in a team, others will possibly be using the code you write. They'll be most happy when they code to your (stable) interfaces, and you'll be happy when you have the freedom to change your implementations (hidden behind the interface) without breaking your team's code. It's a variant of information hiding (interfaces are public, implementations are hidden from the client programmers). Read more about protected variations.

Also see this related question about coding to an Interface.



回答24:

There are so many purposes for using an interface.

  1. Use in polymorphic behavior. Where you want to call specific methods of a child class with an inteface having a reference to the child class.

  2. Having a contract with classes to implement all of the methods where it is necessary, like most common use is with COM objects , where a wrapper class is generated on a DLL which inherits the interface; these methods are called behind the scenes, and you just need to implement them but with the same structure as defined in the COM DLL which you can only know through the interface that they expose.

  3. To reduce memory usage by loading specific methods in a class. Like if you have three business objects and they are implemented in a single class, you can use three interfaces.

E.g IUser, IOrder, IOrderItem

public interface IUser()
{

void AddUser(string name ,string fname);

}

// Same for IOrder and IOrderItem
//


public class  BusinessLayer: IUser, IOrder, IOrderItem

{    
    public void AddUser(string name ,string fname)
    {
        // Do stuffs here.
    }

    // All methods from all interfaces must be implemented.

}

If you only want to add an user, do like this:

IUser user = new (IUser)BusinessLayer();

// It will load  all methods into memory which are declared in the IUser interface.

user.AddUser();