Question

My question is regarding the polymorphic Open-Closed Principle.

Say I have the following client:

public class Client {

    private Server server;

    public Client(Server server) {
        this.server = server;
    }

    public void purchase() {
        server.processPurchase(new Purchase());
    }
}

This is the abstraction for the server:

public interface Server {

    void processPurchase(Purchase purchase);
}

And the implementation for the server:

public class ServerImpl implements Server {

    @Override
    public void processPurchase(Purchase purchase) {
        System.out.println("Processing purchase" + purchase);
        processPayment(purchase);
    }

    private void processPayment(Purchase purchase) {
        System.out.println("Processing payment" + purchase);
    }
}

This minimalist use case is about performing a purchase.

Now say one wants to perform another action when I process the purchase e.g:

  • add purchase information to a database to be later used for machine learning suggestions
  • mail a confirmation email to the user
  • etc.

What would be the best way to achieve the change whilst still respecting the OCP ?

My first idea is to write a second implementation and swap it from the first one as follows:

public class ServerImpl2 implements Server {

    @Override
    public void processPurchase(Purchase purchase) {
        System.out.println("Processing purchase" + purchase);
        processPayment(purchase);
        sendConfirmationEmail(purchase);
    }

    private void processPayment(Purchase purchase) {
        System.out.println("Processing payment" + purchase);
    }

    private void sendConfirmationEmail(Purchase purchase) {
        System.out.println("Sending confirmation email");
    }
}

Is there another way ? Any input or suggestions welcome.

Was it helpful?

Solution

Polymorphic Open-closed principle states that you should override methods deriving from interfaces and not implementation.

By adding private method calls inside your implementation, you are not violating this in the slightest. This is only stating that should you ever derive from ServerImpl, you would only ever really need to override processPurchase method and not, say, sendConfirmationEmail for instance as this is an implementation-specific method.

It is absolutely fine to have private methods to help realize the public callable method processPurchase.

OTHER TIPS

The open closed principle can be realised through the usage of interfaces. Using interfaces let’s you have great control on extending your classes, whilst also keeping you from modifying abilities from parents, etc.

I’m on mobile at the moment but below is an example.

Let’s say you have the following:

interface IEat
{
     void Eat(Food food);
}

abstract class Animal {} : IEat
{
    abstract void Eat() { ... }
}

Now we want to create a predator subtype which would extend functionality of animal, but importantly not modify the behaviour...

We can achieve this through using another interface (notably NOT through overwriting Animals functions).

interface Predator
{
    void HuntForFood()
}

class Predator : IEat, IPredator
{
    void Eat(Food food)
     {
          this.HuntForFood();
          // Carry on eating.
     }

     void HuntForFood()
     {
           ...
     }
}
Licensed under: CC-BY-SA with attribution
scroll top