简体   繁体   中英

concept of Interfaces in C#

I am trying to get a better understanding of the interfaces in C# and other OOP languages. What does an interface do? Why is it needed? I know c# and Java do not allow multiple inheritance. Most books say interfaces are the one way to get around the single inheritance restriction and allow different classes to have a common functionality. Interfaces just define the methods and forces the classes to implement them. Why not have the class define and implement methods itself without dealing with an interface? For example:

4: using System;
5:
6: public interface IShape
7: {
8:    double Area();
9:    double Circumference();
10:   int Sides();
11: }
12:
13: public class Circle : IShape
14: {
15:    public int x;
16:    public int y;
17:    public double radius;
18:    private const float PI = 3.14159F;
19:
20: public double Area()
21: {
22:    double theArea;
23:    theArea = PI * radius * radius;
24:    return theArea;
25: }
.
.
.

Why can't the Circle class define and implement the Area(), Circumference() and Sides() methods itself? If a square class inherits the IShape, the Circumference() methods will have to be unimplemented. Am I way off in my understanding of interfaces?

Interfaces are for when you want to say "I don't care how you do it, but here's what you need to get done". Refer this link for more clarifications.

An object in C# may have functions that are actually a composite of different categories; a classic example of this is the Teacher example:

多重继承

In this example, the Teacher has the characteristics of a Person (eg Eye Colour) (although I've had some teachers that may break this example) and the characteristics of an Employee (eg Salary)

C# doesn't allow for multiple inheritance so instead we look to the idea of composition using interfaces. It is often described this way:

Inheritance implies that if Cat inherits from Animal then Cat "is-a" Animal

Composition implies that if Cat implements Noise then Cat "has-a" Noise

Why is this distinction important? Well, imagine our Cat. We could actually have Cat inherit from Feline, which in turn inherits from Animal. One day, we decide that we are going to support other types of Animal, so we decide to revise Animal, but then we realise that we are going to be pushing these changes to every other sub type. Our design, and hierarchy is suddenly quite complicated, and, if we didn't get it right to begin with, we have to extensively redesign all of our child classes.

A rule is to Prefer Composition over Inheritance , but note the use of the word Prefer - it's important, because it doesn't mean that we should just use composition, but instead, our design should consider when inheritance is useful and when composition is useful too. It also reminds us that sticking every possible method ever in the base class is a bad idea.

I like your shape example. Consider:

小型分拣机

Our ShapeSorter might have a method like this:

public bool Sort(Shape shape)
{
  foreach(Hole hole in Holes)
  {
     if(Hole.Type == HoleType.Circular && shape is Circle)
     {
         return true;
     }
     if(Hole.Type == HoleType.Square && shape is Square)
     {
         return true;
     }
     if(Hole.Type == HoleType.Triangular && shape is Triangle)
     {
         return true;
     }
  }

  return false;

}

Or, we could do some slight inversion of control:

public bool Sort(Shape shape, Hole hole)
{
   return hole.Accepts(shape); //We  end up pushing the `if` code into Hole
}  

Or some variant thereof. We are already writing a lot of code that relies on us knowing the exact sort of Shape. Imagine how tedious it gets to maintain when you have one of these:

大型分拣机

So, instead, we think to ourselves - is there a more generic way we can describe our problem by distilling it down to the relevant properties?

You've called it IShape:

public interface IShape{
  double Area {get;}
  double Perimeter { get; } //Prefer Perimeter over circumference as more applicable to other shapes
  int Sides { get; }
  HoleType ShapeType { get; }
}

Our Sort method would then become:

public Hole Sort(IShape shape)
{
   foreach(Hole hole in Holes)
   {
      if(hole.HoleType == shape.ShapeType && hole.Area >= shape.Area)
      {
         return hole;
      }
   }
   return null;
}

Which looks neater, but isn't really anything that couldn't have been done via Shape directly.

The truth is that there is no truth. The most common approach will involve using both inheritance and composition, as many things in the real world will be both of a type and will also have other attributes best described by an interface. The most important thing to avoid is sticking every possible method in the base class and having huge if statements to work out what the derived types can and can't do - this is a lot of code that is hard to maintain. Also, putting too much functionality in base classes can lead to setting your code in concrete - you wont want to revise things later because of all the potential side effects.

In this case yes you can definitely do it. But there are some cases like mouse listeners which are interfaces. There are dummy methods that are declared in them. Later on in your program as a developer, you override these methods and implement your own custom logic.

Source : The MouseListener interface defines five methods: mouseClicked, mouseEntered, mouseExited, mousePressed, and mouseReleased. They are all void methods and take a single MouseEvent object as their parameter. Remember that you must define all five of these methods; otherwise, your class must be declared as abstract. The MouseListener interface does not track events such as the explicit movement of the mouse.

Why can't the Circle class define and implement the Area(), Circumference() and Sides() methods itself?

well it can, but it will be independent of the interface. One of the main advantage interfaces gives you is "Runtime binding".

For your current example you only have one class Circle , lets say you create another class Rectangle and both of your classes implements IShape . Later in your code at runtime you can create object of Circle and Rectangle and have it inside an instance type variable.

IShape shape;

if(User needs a Circle) // just a sample test to show runtime binding. shape = new Circle(); else shape = new Rectangle();

now when you do

double area = shape.Area();

You will get Area of the shape. At runtime you will not know whether area will be required for Rectangle or a Circle . But the interface object will call the implemented method of the shape it is holding reference of.

An interface is a guarantee that an object implements a specific set of methods or properties. Yes, your shape classes can implement those methods without an interface, but there is no way to tell other code that it implements them, and you could accidentally forget to implement one, or change its parameters.

An interface is a definition. It allows other code to know what the definition is, without knowing what the implementation is. In otherwords, it's not that the circle can't implement the methods, it's that if a circle implements the interface it guarantees that it implements the methods.

For instance, you might have an interface called IWriter. IWriter has one method:

public interface IWriter
{
    void Write(string s);
}

Notice how generic that is. It doesn't say WHAT it is writing, or how it's writing... Only that it writes.

You can then have concrete methods that implement IWriter, such as MemoryWriter, ConsoleWriter, PrinterWriter, HTMLWriter, etc... each writes in a different way, but they all implement the same simple interface with only one method.

public class ConsoleWriter : IWriter
{
    public void Write(string s) {
         Console.WriteLine(s);
    }
}

public class MemoryWriter : IWriter
{
    public void Write(string s) {
        // code to create a memory object and write to it
    }
}

You could accomplish the same thing with a baseclass, but this would rely on an actual implementation, and would create dependencies that you may not want. Interfaces decouple implementation from definition.

Regarding squares not having circumferences and circles not having sides... That just means your IShape definition is not well designed. You're trying to make objects fit into a single definition that may not apply.

An interface is also known as a contract which will be used during interaction between two or more classes.

In this case, when a class is said to be implementing IShape , the caller will know that the class has all the methods defined in the contract called IShape . The caller will not worry whether the class is Square / Rectangle / Circle .

To answer your question

If a square class inherits the IShape , the Circumference() methods will have to be unimplemented.

You need to design your interfaces such that it is generic enough. In this case the interface should have a method called Perimeter instead of circumference.

For the sides property, I believe the circle should return a predefined constant such as int.MaxValue to represent infinity.

To understand the benefit of the interface, you need to see how the caller would be invoking these methods.

eg

public double DisplayArea(IShape shape)
{
    Console.WriteLine(shape.Area().ToString());
}

you can invoke the above method by

//Code to create a Circle
this.DisplayArea(circle);

//Code to create a Square
this.DisplayArea(square);

This is possible because, DisplayArea knows that any object of type IShape will have a method called Area which will return a double . So, it will not worry about the class name at all. In future if you implement Ellipse class and make it implement the interface IShape , the DisplayArea method will work without any modifications.

Definitely, you can add method to class by your own without implementing an interface. But interfaces make sure that you do without leaving it to your wish. This is something like obligation minus arbitration. As said, interface is contract which must be fulfilled and what's upto you is how you fulfill.

In real world you'll be working with not only circle. You'll need other shapes such as rectangles/squares etc. Interfaces allow you to define some common contract which you'll be using within your application and you may then add new shapes easily. And you won't be forced to change your code drastically when adding a new shape - you just implement IShape interface and you're done (well, some changes will be required but not that much).

The difference between implementing an Interface and Inheritance is that Inheritance specifies an "Is" behaviour, as in "A 'is' also B' (A Cat 'Is' also an animal). An Interface implements more of a "Has" (or Does) behaviour. (A bird 'has' wings, and Aeroplane also 'has' wings). This is gross simplification but you get the idea.

That is why in these languages you can only inherit from one object but implement many interfaces. Interface provides more of a Mixin functionality (it lets you mix in various things like just like an artist mixes paint).

Neither Inheritance or Interface is better than the other. It really is up to you to design your object structure so that you use the right constructs.

For example. You wouldn't inherit your Aeroplane class from a Bird class just because they both can fly. Yes an Aeroplane and a Bird have a lot in common, but an Aeroplane is not a Bird. (having said that the semantics might differ in your particular application you might not care to make that distinction or you might never have to deal with Aeroplanes in your application). Here you would have an interface that says something like

public Interface ICanFly
{
    void Fly();
    void Land();
}

This way both aeroplanes and birds can implement the ICanFly interface without trying to pretend an aeroplane is a bird. You might have some other classes that only care about whether something flys or not regardless of whether it is man made or natural. Lets say you have a Radar class with Track method

public class Radar
{
    // This method doesn't care whether the object is a bird or plane.
    public void Track(ICanFly flyingObject)
    {

    }
}

And you can can have other classes that specifically apply to animals

public class MigrationTracker
{
    // I only deal with birds since aeroplanes don't migrate.
    public void Track(Bird birdsToTrack)
    {

    }
}

As you can see, Interfaces and Inheritance provide different options in how you want to design your classes, but it's up to you to use them wisely. For example, you application for the local zoo might never have to deal with aeorplanes, in which case the flying functionality can just be added to the bird class and inherited rather than being mixed in with interfaces.

Why not have the class define and implement methods itself without dealing with an interface?

Imagine Circle class ,Method name is AreaOfCircle

Rectangle method name is 'AreaOfRectangle'

Square do not have any method like 'Area'

apart from above discussion, there is no uniformity in Method name. There is no guarantee that important method are implemented across all those classes.

It will require lot of effort to verify important methods across all classes. If Interface is implemented then simply find he reference of Interface, then it is guaranteed that those method with same name must be implemented.

So the interface contract is guaranteed. Also it is very easy to implemented any new contract of interface across inheriting classes.

If a square class inherits the IShape, the Circumference() methods will have to be unimplemented.

It is wrong practice to put all signature/contract in single interface.When I know that polygon such as square and rectangle cannot implement Circumference() .I will put Circumference() in different interface.

So interface help you organise code ,hence it help in achieving various design pattern.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM