Abstraction

Abstraction in C# is one of the four fundamental principles of object-oriented programming (OOP), alongside encapsulation, inheritance, and polymorphism. It simplifies complex systems by modeling classes that are relevant to the problem at hand. Abstraction allows developers to focus on the essential features of an object while hiding the intricate implementation details.

Key Concepts of Abstraction

Abstract Classes:
Abstract classes provide a common definition for a base class that can be shared by multiple derived classes. It is important to note that an abstract class cannot be instantiated directly. An abstract class can contain both abstract methods (which are methods without a body) and concrete methods (which have a complete implementation).

Abstract Methods:
Abstract methods are declared within an abstract class and do not include an implementation. Derived classes must provide an implementation for these abstract methods. This enforces a contract that ensures certain functionality is implemented in all derived classes.

Interfaces:
Interfaces define a contract that the implementing classes must adhere to. They consist solely of method signatures (without any implementation) and property definitions. A class is allowed to implement multiple interfaces, promoting flexibility and enabling the use of various behaviors in a single class.

These concepts of abstraction play a crucial role in designing systems that are easier to manage and extend. By focusing on what an object does rather than how it does it, programmers can create cleaner, more efficient, and more intuitive code.

Example

using System;

// Abstract class
abstract class Shape
{
  // Abstract method (no implementation)
  public abstract double GetArea();

 
// Abstract method (no implementation)
  public abstract double GetPerimeter();

 
// Concrete method with implementation
  public void DisplayInfo()
  {
      Console.WriteLine("This is a shape.");
  }
}

// Derived class
class Circle : Shape
{
  // Field
  private double radius;

 
// Constructor
  public Circle(double radius)
  {
      this.radius = radius;
  }

    // Implementing the abstract method
  public override double GetArea()
  {
      return Math.PI * radius * radius;
  }

    // Implementing the abstract method
  public override double GetPerimeter()
  {
      return 2 * Math.PI * radius;
  }

    // Method specific to Circle
  public void DisplayCircleInfo()
  {
      Console.WriteLine($"Circle with radius: {radius}");
  }
}

// Derived class
class Rectangle : Shape
{
  // Fields
  private double width;
  private double height;

    // Constructor
  public Rectangle(double width, double height)
  {
      this.width = width;
      this.height = height;
  }

    // Implementing the abstract method
  public override double GetArea()
  {
      return width * height;
  }

    // Implementing the abstract method
  public override double GetPerimeter()
  {
      return 2 * (width + height);
  }

    // Method specific to Rectangle
  public void DisplayRectangleInfo()
  {
      Console.WriteLine($"Rectangle with width: {width}, height: {height}");
  }
}

class Program
{
  static void Main()
  {
      // Creating instances of Circle and Rectangle
      Shape circle = new Circle(5.0);
      Shape rectangle = new Rectangle(4.0, 6.0);

        // Displaying area and perimeter of the shapes
      Console.WriteLine("Circle:");
      Console.WriteLine($"Area: {circle.GetArea()}");
      Console.WriteLine($"Perimeter: {circle.GetPerimeter()}");
      Console.WriteLine("\nRectangle:");
      Console.WriteLine($"Area: {rectangle.GetArea()}");
      Console.WriteLine($"Perimeter: {rectangle.GetPerimeter()}");

        // Calling the concrete method from the abstract class
      circle.DisplayInfo();
      rectangle.DisplayInfo();

        // Accessing methods specific to Circle and Rectangle
      ((Circle)circle).DisplayCircleInfo();
      ((Rectangle)rectangle).DisplayRectangleInfo();
  }
}

Explanation of the Example

  • Abstract Class (Shape): The Shape class is declared as abstract and includes two abstract methods: ‘GetArea’ and ‘GetPerimeter’. It also features a concrete method, ‘DisplayInfo’, which has its own implementation.
  • Derived Class (Circle): The Circle class inherits from Shape and provides implementations for the abstract methods ‘GetArea’ and ‘GetPerimeter’. Additionally, it includes a specific method called ‘DisplayCircleInfo’ to show information about the circle.
  • Derived Class (Rectangle): The Rectangle class also inherits from Shape and offers implementations for the abstract methods ‘GetArea’ and ‘GetPerimeter’. It contains a specific method known as ‘DisplayRectangleInfo’ to present information about the rectangle.
  • Main Method: In the main method, we create instances of Circle and Rectangle and assign them to variables of type Shape. We then call the ‘GetArea’ and ‘GetPerimeter’ methods on these instances, demonstrating polymorphism through abstraction. Furthermore, we invoke the ‘DisplayInfo’ method from the abstract class, showcasing its usability by derived classes. Finally, we cast the Shape variables to their specific types to access and call their respective methods, ‘DisplayCircleInfo’ and ‘DisplayRectangleInfo’.

Benefits of Abstraction

  1. Simplification:
    • Abstraction simplifies complex systems by breaking them down into more manageable and understandable parts. It enables you to focus on high-level functionalities instead of getting bogged down with low-level implementation details.
  2. Code Reusability:
    • Abstract classes and interfaces promote code reuse by providing a common foundation that can be extended or implemented by multiple derived classes. Shared functionalities can be defined in abstract classes, making them reusable in derived classes.
  3. Maintainability:
    • Abstraction enhances code maintainability by separating the interface from the implementation. Changes made to the implementation do not affect the interface, which minimizes the impact of changes on the overall system.
  4. Flexibility:
    • Abstraction offers flexibility by allowing you to define abstract methods that must be implemented by derived classes. This approach lets you establish a common interface while facilitating various implementations.
Post a comment

Leave a Comment

Scroll to Top