Amit Kumar Mondal bio photo

Amit Kumar Mondal

Java Enthusiast

Email Facebook Google+ LinkedIn Github

Overview

Overview

Due to the current inclusion of Java 8 Functional Programming Paradigm in today’s world, people still wonder how it could collaborate well with the existing object oriented approach. That’s why I would love to demonstrate a concrete example of command pattern using Java 8 Lambda Expression.

Command Pattern

</a>

The Problem Domain

An editor or IDE has gallons of actions or commands such as open, close, save etc. Each and every time, someone needs to develop a new command for the IDE, it should conform to the Open-Closed principle - Open for Extension and Closed for Modification. So, now our design decision should be effective enough to allow extensions to the applications so that anyone can easily plug-in new command to the IDE.

OOP way

First of all, I would love to tell you about how it can be achieved using the object oriented way.

Command

public interface Command {

	public void perform();

}

Concrete Command - Open

public final class Open implements Command {

	private final Editor editor;

	public Open(final Editor editor) {
		super();
		this.editor = editor;
	}

	@Override
	public void perform() {
		this.editor.open();
	}

}

Concrete Command - Save

public final class Save implements Command {

	private final Editor editor;

	public Save(final Editor editor) {
		super();
		this.editor = editor;
	}

	@Override
	public void perform() {
		this.editor.save();
	}

}

Receiver

public interface Editor {

	public void close();

	public void open();

	public void save();

}

Concrete Receiver

public final class MockEditor implements Editor {

	private final List<String> actions = Lists.newArrayList();

	@Override
	public void close() {
		this.actions.add("close");
	}

	@Override
	public void open() {
		this.actions.add("open");
	}

	@Override
	public void save() {
		this.actions.add("save");
	}

}

Invoker

public final class Macro {

	private final List<Command> commands;

	public Macro() {
		this.commands = Lists.newArrayList();
	}

	public void record(final Command command) {
		this.commands.add(command);
	}

	public void run() {
		this.commands.forEach(Command::perform);
	}

}

Client

public final class Client {

	public static void main(final String[] args) {
		final Macro macro = new Macro();
		final Editor editor = new MockEditor();
		final Command openCommand = new Open(editor);
		final Command saveCommand = new Save(editor);

		macro.record(openCommand);
		macro.record(saveCommand);

		macro.run();
	}

}

Functional Way

So far, we have seen the object-oriented approach in solving our defined problem using Command Pattern. Now, we would try to solve it using Functional Programming Paradigm which I believe would be more concise and better solution.

Command

public interface Command {

	public void perform();

}

Receiver

public interface Editor {

	public void close();

	public void open();

	public void save();

}

Invoker

public final class Macro {

	private final List<Command> commands;

	public Macro() {
		this.commands = Lists.newArrayList();
	}

	public void record(final Command command) {
		this.commands.add(command);
	}

	public void run() {
		this.commands.forEach(Command::perform);
	}

}

Client

public final class Client {

	public static void main(final String[] args) {
		final Macro macro = new Macro();
		final Editor editor = new MockEditor();

		macro.record(() -> new Open(editor));
		macro.record(() -> new Save(editor));

		macro.run(); // 1st way

		macro.record(() -> editor.open());
		macro.record(() -> editor.save());

		macro.run(); // 2nd way

		macro.record(editor::open);
		macro.record(editor::save);

		macro.run(); // 3rd way
	}

}

Benefits

You can clearly see that I didn’t write any concrete implementation class of the commands. I have only passed those implementations as behaviors to the record method as it accepts SAM (Single Abstract Method) Interface (Command).