Skip to Content
Course content

303: Practice Exercise: Refactoring a Procedural Program into OOP

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I see this all the time when developers transition from languages like C or Python to Java: the belief that Object-Oriented Programming is simply a way of organizing your functions into "folders" called classes. You might think that as long as your methods are inside a class, you're "doing OOP."

Classes Aren't Just Folders for Your Methods

Let's look at a piece of code that perfectly illustrates this mistake. Imagine we're building a simple system to track a library's books. A developer with the "class-as-folder" mindset would write something like this:

public class LibrarySystem {
    // Data is kept separate from the logic
    public static String bookTitle = "The Great Gatsby";
    public static boolean isCheckedOut = false;

    public static void checkOutBook() {
        isCheckedOut = true;
        System.out.println(bookTitle + " has been checked out.");
    }

    public static void returnBook() {
        isCheckedOut = false;
        System.out.println(bookTitle + " has been returned.");
    }
}

Technically, this is in a Java class. But conceptually? This is 100% procedural code. The class is acting as a glorified namespace. We have global state (the static variables) and functions that manipulate that state from the outside. If we wanted to add a second book, this entire structure collapses unless we start managing messy arrays of strings and booleans indexed by integers.

Letting Objects Manage Their Own State

The "Aha!" moment comes when you realize that OOP isn't about where the method lives, but what the method has access to. In a true OOP design, the data and the logic that manipulates that data are bundled together. The object becomes a self-contained unit that is responsible for its own internal consistency.

Instead of a "System" that manages a book, we create a Book object. The logic for checking out a book doesn't belong in a manager class; it belongs to the book itself. Honestly, if you find yourself writing a class that's just a collection of static methods acting on external data, you're just writing C with extra steps.

Here is how we refactor that logic to be truly object-oriented:

public class Book {
    private String title;
    private boolean isCheckedOut;

    public Book(String title) {
        this.title = title;
        this.isCheckedOut = false;
    }

    public void checkOut() {
        if (this.isCheckedOut) {
            System.out.println("Sorry, " + title + " is already gone.");
            return;
        }
        this.isCheckedOut = true;
        System.out.println("You have checked out " + title);
    }

    public void returnBook() {
        this.isCheckedOut = false;
        System.out.println("Thank you for returning " + title);
    }
}

Notice the difference. The Book object now "owns" its state. We've used private modifiers to ensure that no one can manually flip the isCheckedOut flag to true without going through the checkOut() method. This is encapsulation. We aren't just organizing code; we're protecting the integrity of the data.

When you approach your refactoring exercises, ask yourself: "Is this method acting on a piece of data that should actually belong to the object itself?" If the answer is yes, move the method inside that object's class and make the data private. That's the core of the shift from procedural to OOP.




📋 Practical Task

Refactoring the Warehouse Inventory Tracker

Below is a procedural implementation of a warehouse inventory system. Currently, it uses a WarehouseManager class as a "folder" for static methods and arrays to track item names and their quantities. This is fragile and difficult to scale.

public class WarehouseManager {
    public static String[] itemNames = {"Laptop", "Mouse", "Keyboard"};
    public static int[] itemQuantities = {10, 50, 25};

    public static void shipItem(int index, int amount) {
        if (itemQuantities[index] >= amount) {
            itemQuantities[index] -= amount;
            System.out.println("Shipped " + amount + " of " + itemNames[index]);
        } else {
            System.out.println("Insufficient stock for " + itemNames[index]);
        }
    }

    public static void restockItem(int index, int amount) {
        itemQuantities[index] += amount;
        System.out.println("Restocked " + itemNames[index] + ". New total: " + itemQuantities[index]);
    }
}

Your Task:

  • Create a new Product class.
  • Move the name and quantity into the Product class as private fields.
  • Move the shipItem and restockItem logic into the Product class as instance methods (remove the index parameters, as the method will now operate on this specific product).
  • In a Main class, instantiate three different Product objects and demonstrate shipping and restocking them.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.