Lesson 6
Abstraction
Welcome to Abstraction

Welcome back! Previously, you delved into polymorphism and learned how to create more flexible code structures using classes and inheritance. In this session, we will take a step further and explore a crucial aspect of Object-Oriented Programming: Abstraction.

Understanding Abstract Classes and Abstract Methods

Abstract classes and abstract methods are essential tools for achieving abstraction. They allow you to define a common interface for a group of derived classes, ensuring that specific methods are implemented. This approach helps you write more robust and scalable programs.

1. Defining an Abstract Class

Let's revisit some of the key concepts through the following code example:

Java
1// Define an abstract class Shape. Note that the abstractness is achieved by having at least one abstract method. 2abstract class Shape { 3 // Field variables 4 private String color; 5 6 // Constructor to initialize color 7 public Shape(String color) { 8 this.color = color; 9 } 10 11 // Abstract methods for calculating the area and perimeter 12 abstract double area(); 13 abstract double perimeter(); 14 15 // Concrete method to get the color 16 public String getColor() { 17 return color; 18 } 19}

In this snippet, we define an abstract class Shape with a field variable color, a constructor to initialize the color, and a concrete method getColor to retrieve the color. The class also contains two abstract methods: area and perimeter. An abstract class can have field variables and fully defined methods, but it must contain at least one abstract method, making it impossible to instantiate directly.

2. Implementing the Abstract Methods in Derived Classes

Next, we create concrete classes that extend the abstract class Shape:

Circle Class
Java
1// Define a Circle class that inherits from Shape 2class Circle extends Shape { 3 private double radius; 4 5 // Constructor to initialize the radius and color 6 Circle(double radius, String color) { 7 super(color); 8 this.radius = radius; 9 } 10 11 // Implement the area and perimeter methods 12 @Override 13 double area() { 14 return Math.PI * radius * radius; 15 } 16 17 @Override 18 double perimeter() { 19 return 2 * Math.PI * radius; 20 } 21}

Here, the Circle class inherits from Shape and provides concrete implementations for the abstract methods area and perimeter. It also includes a constructor to initialize the radius and color by calling the super constructor from the Shape class.

Rectangle Class
Java
1// Define a Rectangle class that inherits from Shape 2class Rectangle extends Shape { 3 private double width, height; 4 5 // Constructor to initialize the width, height, and color 6 Rectangle(double width, double height, String color) { 7 super(color); 8 this.width = width; 9 this.height = height; 10 } 11 12 // Implement the area and perimeter methods 13 @Override 14 double area() { 15 return width * height; 16 } 17 18 @Override 19 double perimeter() { 20 return 2 * (width + height); 21 } 22}

Similarly, the Rectangle class inherits from Shape and implements the necessary methods area and perimeter. It also includes a constructor to initialize the width, height, and color, ensuring that all necessary attributes are properly initialized.

3. Using the Abstract Class and Derived Classes

Finally, let's see how we can use these classes in a main method:

Java
1public class Main { 2 public static void main(String[] args) { 3 Circle circle = new Circle(5, "Red"); 4 Rectangle rectangle = new Rectangle(4, 6, "Blue"); 5 6 System.out.println("Circle Area: " + circle.area() + ", Perimeter: " + circle.perimeter() + ", Color: " + circle.getColor()); 7 System.out.println("Rectangle Area: " + rectangle.area() + ", Perimeter: " + rectangle.perimeter() + ", Color: " + rectangle.getColor()); 8 9 // Using a Shape reference to a Circle object 10 Shape shape = new Circle(3, "Green"); 11 System.out.println("Shape Area: " + shape.area() + ", Perimeter: " + shape.perimeter() + ", Color: " + shape.getColor()); 12 13 // Uncommenting the following line will cause an error as you can't instantiate an abstract class 14 // Shape invalidShape = new Shape("Yellow"); 15 } 16}

By running the main method, you can see how the Circle and Rectangle classes correctly implement the area and perimeter methods defined in the Shape abstract class, while also utilizing the getColor method. The example also demonstrates polymorphism by using a Shape reference to a Circle object.

It's important to note that attempting to instantiate an abstract class directly, as shown by the commented-out line, will result in a compilation error. This reinforces the concept that abstract classes are meant to be subclassed, not instantiated.

Why It Matters

Abstract classes and abstract methods offer a way to enforce certain patterns and rules in your code. They allow you to design a system where different types of objects can be treated uniformly while ensuring that specific behaviors are implemented in each derived class.

By mastering abstract classes and abstract methods, you'll be able to:

  1. Create more organized and readable code: You'll have a clear structure that dictates how certain methods should behave.
  2. Encourage code reusability: Common code can reside in abstract base classes, reducing redundancy.
  3. Enhance flexibility: Easily add new types of derived classes without modifying existing code — a key principle of software design.

Intrigued? Let's move on to the practice section and solidify these concepts together. You're on your way to becoming proficient in building sophisticated and maintainable systems!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.