C# > Object-Oriented Programming (OOP) > Polymorphism > Interfaces and Implementation
Polymorphism with Interfaces: Shape Area Calculation
This code snippet demonstrates polymorphism in C# using interfaces. It defines an IShape
interface with a method to calculate the area, and then implements this interface in different shape classes (Circle
, Rectangle
, and Triangle
). This allows you to treat different shape objects uniformly through the IShape
interface, showcasing runtime polymorphism.
Interface Definition: IShape
This code defines an interface named IShape
. Interfaces in C# define a contract that classes can implement. Any class that implements IShape
must provide an implementation for the CalculateArea()
method. This enforces a consistent structure for any object representing a shape.
public interface IShape
{
double CalculateArea();
}
Class Implementation: Circle
This code defines a class named Circle
that implements the IShape
interface. It has a private field _radius
to store the radius of the circle. The constructor initializes the radius, and the CalculateArea()
method calculates the area of the circle using the formula πr². Critically, it provides a concrete implementation of the method declared in the interface.
public class Circle : IShape
{
private double _radius;
public Circle(double radius)
{
_radius = radius;
}
public double CalculateArea()
{
return Math.PI * _radius * _radius;
}
}
Class Implementation: Rectangle
This code defines a class named Rectangle
that also implements the IShape
interface. It has private fields _width
and _height
to store the dimensions of the rectangle. The constructor initializes these dimensions, and the CalculateArea()
method calculates the area of the rectangle by multiplying width and height.
public class Rectangle : IShape
{
private double _width;
private double _height;
public Rectangle(double width, double height)
{
_width = width;
_height = height;
}
public double CalculateArea()
{
return _width * _height;
}
}
Class Implementation: Triangle
This code defines a class named Triangle
that implements the IShape
interface. It has private fields _base
and _height
to store the base and height of the triangle. The constructor initializes these dimensions, and the CalculateArea()
method calculates the area of the triangle by multiplying 0.5 with base and height.
public class Triangle : IShape
{
private double _base;
private double _height;
public Triangle(double baseValue, double height)
{
_base = baseValue;
_height = height;
}
public double CalculateArea()
{
return 0.5 * _base * _height;
}
}
Polymorphic Usage
This code demonstrates how the IShape
interface enables polymorphism. We create instances of Circle
, Rectangle
and Triangle
, but we store them as IShape
objects. This allows us to treat them uniformly. The loop iterates through an array of IShape
objects, calling CalculateArea()
on each. The correct CalculateArea()
method is called based on the actual type of the object at runtime (e.g., the Circle
version is called for the circle object). This is polymorphism in action.
IShape circle = new Circle(5);
IShape rectangle = new Rectangle(4, 6);
IShape triangle = new Triangle(3, 8);
Console.WriteLine("Circle Area: " + circle.CalculateArea());
Console.WriteLine("Rectangle Area: " + rectangle.CalculateArea());
Console.WriteLine("Triangle Area: " + triangle.CalculateArea());
// Demonstrating polymorphism in a collection
IShape[] shapes = { circle, rectangle, triangle };
double totalArea = 0;
foreach (IShape shape in shapes)
{
totalArea += shape.CalculateArea();
}
Console.WriteLine("Total Area: " + totalArea);
Concepts Behind the Snippet
This snippet illustrates several key OOP concepts:
Polymorphism allows for more flexible and maintainable code because you can add new shape types without modifying the code that uses the IShape
interface.
Real-Life Use Case
Imagine a drawing application. You might have various drawing tools (e.g., lines, circles, squares). Each tool could be represented by a class that implements an IDrawable
interface. The application can then treat all tools uniformly through the IDrawable
interface, regardless of their specific implementation details. This makes it easy to add new tools without changing the core drawing logic.
Best Practices
Interview Tip
Be prepared to explain the difference between interfaces and abstract classes, and when to use each. Also, be ready to discuss the benefits of using interfaces for achieving polymorphism.
When to Use Them
Use interfaces when you want to define a contract that multiple unrelated classes can implement. This is especially useful when you need to treat objects of different types uniformly. Interfaces are also helpful for decoupling components and promoting loose coupling.
Memory Footprint
The memory footprint of interfaces themselves is minimal. The primary overhead comes from the objects that implement the interface. Each object will store a reference to its type information (used for dynamic dispatching of methods), which contributes to its memory footprint.
Alternatives
dynamic
keyword): Bypasses compile-time type checking and relies on runtime type resolution. This can be useful for interoperability with dynamic languages, but it sacrifices compile-time safety.
Pros
Cons
FAQ
-
What is the difference between an interface and an abstract class?
An interface defines a contract that classes must implement, without providing any implementation details. An abstract class can provide partial implementations and abstract methods that subclasses must implement. A class can implement multiple interfaces, but it can only inherit from a single abstract class. -
Why use interfaces instead of concrete classes?
Using interfaces promotes loose coupling, making the code more flexible and maintainable. It allows you to treat objects of different types uniformly and facilitates unit testing. -
Can an interface contain fields?
No, interfaces cannot contain fields (instance variables). They can only contain method declarations, properties, events, and indexers.