Can someone explain what a functor is and provide a simple example?
A function object is just that. Something which is both an object and a function.
Aside: calling a function object a "functor" is a serious abuse of the term: a different kind of "functors" are a central concept in mathematics, and one that has a direct role in computer science (see "Haskell Functors"). The term is also used in a slightly different way in ML, so unless you are implementing one of these concepts in Java (which you can!) please stop using this terminology. It makes simple things complicated.
Back to the answer:
Java does not have "first class functions" that is to say, you can not pass a function as an argument to a function. This true at multiple levels, syntactically, in the byte code representation, and in that the type system lacks the "function constructor"
In other words, you can't write something like this:
public static void tentimes(Function f){
for(int i = 0; i < 10; i++)
f();
}
...
public static void main{
...
tentimes(System.out.println("hello"));
...
}
This is really annoying, since we want to be able to do things like have Graphical User Interface libraries where you can associate a "callback" function with clicking on a button.
So what do we do?
Well, the general solution (discussed by the other posters) is to define an interface with a single method that we can call. For example, Java uses an interface called Runnable for these kinds of things all the time, it looks like:
public interface Runnable{
public void run();
}
now, we can rewrite my example from above:
public static void tentimes(Runnable r){
for(int i = 0; i < 10; i++)
r.run();
}
...
public class PrintHello implements Runnable{
public void run{
System.out.println("hello")
}
}
---
public static void main{
...
tentimes(new PrintHello());
...
}
Obviously, this example is contrived. We could make this code a little bit nicer using anonymous inner classes, but this gets the general idea.
Here is where this breaks down: Runnable is only usable for functions that don't take any arguments, and don't return anything useful, so you end up defining a new interface for each job. For example, the interface Comparator in Mohammad Faisal's answer. Providing a more general approach, and one that takes syntax, is a major goal for Java 8 (The next version of Java), and was heavily pushed to be included in Java 7. This is called a "lambda" after the function abstraction mechanism in the Lambda Calculus. Lambda Calculus is both (perhaps) the oldest programming language, and the theoretical basis of much of Computer Science. When Alonzo Church (one of the main founders of computer science) invented it, he used the Greek letter lambda for functions, hence the name.
Other languages, including the functional language (Lisp, ML, Haskell, Erlang, etc), most of the major dynamic languages (Python, Ruby, JavaScript, etc) and the other application languages (C#, Scala, Go, D, etc) support some form of "Lambda Literal." Even C++ has them now (since C++11), although in that case they are somewhat more complicated because C++ lacks automatic memory management, and won't save your stack frame for you.
A functor is an object that's a function.
Java doesn't have them, because functions aren't first-class objects in Java.
But you can approximate them with interfaces, something like a Command object:
public interface Command {
void execute(Object [] parameters);
}
Updated on 18-Mar-2017:
Since I first wrote this JDK 8 has added lambdas. The java.util.function package has several useful interfaces.
From every-time checks, to Functors, to Java 8 Lambdas (sort of)
The problem
Take this example class, which adapts an Appendable into a Writer:
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.io.Writer;
import java.util.Objects;
/**
<P>{#code java WriterForAppendableWChecksInFunc}</P>
**/
public class WriterForAppendableWChecksInFunc extends Writer {
private final Appendable apbl;
public WriterForAppendableWChecksInFunc(Appendable apbl) {
if(apbl == null) {
throw new NullPointerException("apbl");
}
this.apbl = apbl;
}
//Required functions, but not relevant to this post...START
public void write(char[] a_c, int i_ndexStart, int i_ndexEndX) throws IOException {
public Writer append(char c_c) throws IOException {
public Writer append(CharSequence text) throws IOException {
public Writer append(CharSequence text, int i_ndexStart, int i_ndexEndX) throws IOException {
//Required functions, but not relevant to this post...END
public void flush() throws IOException {
if(apbl instanceof Flushable) {
((Flushable)apbl).flush();
}
}
public void close() throws IOException {
flush();
if(apbl instanceof Closeable) {
((Closeable)apbl).close();
}
}
}
Not all Appendables are Flushable or Closeable, but those that are, must also be closed and flushed. The actual type of the Appendable object must therefore be checked in every call to flush() and close() and, when it is indeed that type, it is casted and the function is called.
Admittedly, this isn't the greatest example, since close() is only called once per-instance, and flush() isn't necessarily called that often either. Also, instanceof, while reflective, is not too bad given this particular example-usage. Still, the concept of having to check something everytime you need to do something else is a real one, and avoiding these "every-time" checks, when it really matters, provides significant benefits.
Move all "heavy duty" checks to the constructor
So where do you start? How do you avoid these checks without compromising your code?
In our example, the easiest step is to move all instanceof checks to the constructor.
public class WriterForAppendableWChecksInCnstr extends Writer {
private final Appendable apbl;
private final boolean isFlshbl;
private final boolean isClsbl;
public WriterForAppendableWChecksInCnstr(Appendable apbl) {
if(apbl == null) {
throw new NullPointerException("apbl");
}
this.apbl = apbl;
isFlshbl = (apbl instanceof Flushable);
isClsbl = (apbl instanceof Closeable);
}
//write and append functions go here...
public void flush() throws IOException {
if(isFlshbl) {
((Flushable)apbl).flush();
}
}
public void close() throws IOException {
flush();
if(isClsbl) {
((Closeable)apbl).close();
}
}
}
Now that these "heavy duty" checks are done only once, only boolean checks need to be done by flush() and close(). While certainly an improvement, how can these in-function checks be eliminated entirely?
If only you could somehow define a function which could be stored by the class and then used by flush() and close()...
public class WriterForAppendableWChecksInCnstr extends Writer {
private final Appendable apbl;
private final FlushableFunction flshblFunc; //If only!
private final CloseableFunction clsblFunc; //If only!
public WriterForAppendableWChecksInCnstr(Appendable apbl) {
if(apbl == null) {
throw new NullPointerException("apbl");
}
this.apbl = apbl;
if(apbl instanceof Flushable) {
flshblFunc = //The flushable function
} else {
flshblFunc = //A do-nothing function
}
if(apbl instanceof Closeable) {
clsblFunc = //The closeable function
} else {
clsblFunc = //A do-nothing function
}
}
//write and append functions go here...
public void flush() throws IOException {
flshblFunc(); //If only!
}
public void close() throws IOException {
flush();
clsblFunc(); //If only!
}
}
But passing functions is not possible...at least not until Java 8 Lambdas. So how do you do it in pre-8 versions of Java?
Functors
With a Functor. A Functor is basically a Lambda, but one that is wrapped in an object. While functions cannot be passed into other functions as parameters, objects can. So essentially, Functors and Lambdas are a ways to pass around functions.
So how can we implement a Functor into our writer-adapter? What we know is that close() and flush() are only useful with Closeable and Flushable objects. And that some Appendables are Flushable, some Closeable, some neither, some both.
Therefore, we can store a Flushable and Closeable object at the top of the class:
public class WriterForAppendable extends Writer {
private final Appendable apbl;
private final Flushable flshbl;
private final Closeable clsbl;
public WriterForAppendable(Appendable apbl) {
if(apbl == null) {
throw new NullPointerException("apbl");
}
//Avoids instanceof at every call to flush() and close()
if(apbl instanceof Flushable) {
flshbl = apbl; //This Appendable *is* a Flushable
} else {
flshbl = //?????? //But what goes here????
}
if(apbl instanceof Closeable) {
clsbl = apbl; //This Appendable *is* a Closeable
} else {
clsbl = //?????? //And here????
}
this.apbl = apbl;
}
//write and append functions go here...
public void flush() throws IOException {
flshbl.flush();
}
public void close() throws IOException {
flush();
clsbl.close();
}
}
The "every-time" checks have now been eliminated. But when the Appendable is not a Flushable or not a Closeable, what should be stored?
Do nothing Functors
A do nothing Functor...
class CloseableDoesNothing implements Closeable {
public void close() throws IOException {
}
}
class FlushableDoesNothing implements Flushable {
public void flush() throws IOException {
}
}
...which can be implemented as an anonymous inner class:
public WriterForAppendable(Appendable apbl) {
if(apbl == null) {
throw new NullPointerException("apbl");
}
this.apbl = apbl;
//Avoids instanceof at every call to flush() and close()
flshbl = ((apbl instanceof Flushable)
? (Flushable)apbl
: new Flushable() {
public void flush() throws IOException {
}
});
clsbl = ((apbl instanceof Closeable)
? (Closeable)apbl
: new Closeable() {
public void close() throws IOException {
}
});
}
//the rest of the class goes here...
}
To be most efficient, these do-nothing functors should be implemented as static final objects. And with that, here is the final version of our class:
package xbn.z.xmpl.lang.functor;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.io.Writer;
public class WriterForAppendable extends Writer {
private final Appendable apbl;
private final Flushable flshbl;
private final Closeable clsbl;
//Do-nothing functors
private static final Flushable FLUSHABLE_DO_NOTHING = new Flushable() {
public void flush() throws IOException {
}
};
private static final Closeable CLOSEABLE_DO_NOTHING = new Closeable() {
public void close() throws IOException {
}
};
public WriterForAppendable(Appendable apbl) {
if(apbl == null) {
throw new NullPointerException("apbl");
}
this.apbl = apbl;
//Avoids instanceof at every call to flush() and close()
flshbl = ((apbl instanceof Flushable)
? (Flushable)apbl
: FLUSHABLE_DO_NOTHING);
clsbl = ((apbl instanceof Closeable)
? (Closeable)apbl
: CLOSEABLE_DO_NOTHING);
}
public void write(char[] a_c, int i_ndexStart, int i_ndexEndX) throws IOException {
apbl.append(String.valueOf(a_c), i_ndexStart, i_ndexEndX);
}
public Writer append(char c_c) throws IOException {
apbl.append(c_c);
return this;
}
public Writer append(CharSequence c_q) throws IOException {
apbl.append(c_q);
return this;
}
public Writer append(CharSequence c_q, int i_ndexStart, int i_ndexEndX) throws IOException {
apbl.append(c_q, i_ndexStart, i_ndexEndX);
return this;
}
public void flush() throws IOException {
flshbl.flush();
}
public void close() throws IOException {
flush();
clsbl.close();
}
}
This particular example comes from this question on stackoverflow. A fully working, and fully-documented version of this example (including a testing function) can be found at the bottom of that question-post (above the answer).
Implementing Functors with an Enum
Leaving our Writer-Appendable example, let's take a look at another way to implement Functors: with an Enum.
As an example, this enum has a move function for each cardinal direction:
public enum CardinalDirection {
NORTH(new MoveNorth()),
SOUTH(new MoveSouth()),
EAST(new MoveEast()),
WEST(new MoveWest());
private final MoveInDirection dirFunc;
CardinalDirection(MoveInDirection dirFunc) {
if(dirFunc == null) {
throw new NullPointerException("dirFunc");
}
this.dirFunc = dirFunc;
}
public void move(int steps) {
dirFunc.move(steps);
}
}
Its constructor requires a MoveInDirection object (which is an interface, but could also be an abstract class):
interface MoveInDirection {
void move(int steps);
}
There are naturally four concrete implementations of this interface, one per direction. Here is a trivial implementation for north:
class MoveNorth implements MoveInDirection {
public void move(int steps) {
System.out.println("Moved " + steps + " steps north.");
}
}
Using this Functor is done with this simple call:
CardinalDirection.WEST.move(3);
Which, in our example, outputs this to the console:
Moved 3 steps west.
And here is a full working example:
/**
<P>Demonstrates a Functor implemented as an Enum.</P>
<P>{#code java EnumFunctorXmpl}</P>
**/
public class EnumFunctorXmpl {
public static final void main(String[] ignored) {
CardinalDirection.WEST.move(3);
CardinalDirection.NORTH.move(2);
CardinalDirection.EAST.move(15);
}
}
enum CardinalDirection {
NORTH(new MoveNorth()),
SOUTH(new MoveSouth()),
EAST(new MoveEast()),
WEST(new MoveWest());
private final MoveInDirection dirFunc;
CardinalDirection(MoveInDirection dirFunc) {
if(dirFunc == null) {
throw new NullPointerException("dirFunc");
}
this.dirFunc = dirFunc;
}
public void move(int steps) {
dirFunc.move(steps);
}
}
interface MoveInDirection {
void move(int steps);
}
class MoveNorth implements MoveInDirection {
public void move(int steps) {
System.out.println("Moved " + steps + " steps north.");
}
}
class MoveSouth implements MoveInDirection {
public void move(int steps) {
System.out.println("Moved " + steps + " steps south.");
}
}
class MoveEast implements MoveInDirection {
public void move(int steps) {
System.out.println("Moved " + steps + " steps east.");
}
}
class MoveWest implements MoveInDirection {
public void move(int steps) {
System.out.println("Moved " + steps + " steps west.");
}
}
Output:
[C:\java_code]java EnumFunctorXmpl
Moved 3 steps west.
Moved 2 steps north.
Moved 15 steps east.
I haven't started with Java 8 yet, so I can't write the Lambdas section yet :)
Take concept of function application
f.apply(x)
Inverse
x.map(f)
Call x a functor
interface Functor<T> {
Functor<R> map(Function<T, R> f);
}
Related
I created a factory pattern in my class.
In this class I injected classes which implements Command interface based on incoming String parameter.
Factory class
#Component
#RequiredArgsConstructor
public class CommandFactory {
private final ACommand aCommand;
private final BCommand bCommand;
private final CCommand cCommand;
private final DCommand dCommand;
private final ECommand eCommand;
private final FCommand fCommand;
public Command createCommand(String content) {
if (aCommand.isMatching(content)) {
return aCommand;
} else if (bCommand.isMatching(content)) {
return bCommand;
} else if (cCommand.isMatching(content)) {
return cCommand;
} else if (dCommand.isMatching(content)) {
return dCommand;
} else if (eCommand.isMatching(content)) {
return eCommand;
} else if (fCommand.isMatching(content)) {
return fCommand;
} else {
return null;
}
}
In isMatching() method there are different regex'es and I try to figure out how this incoming String should be processed.
I am looking for a cleaner way to get rid of these sequential if statements. Because whenever I create a new class into this factory I add another if statement.
Maybe Stream can help?
Stream<Command> stream = Stream.of(aCommand, bCommand, cCommand ...);
return stream.filter(x -> x.isMatching(content)).findFirst().orElse(null);
Now every time you add a new class, you just add a new object to the first line.
If you want to get rid of the sequential if statements you can use streams (like user Sweeper suggested) or loops and I would also suggest to return and optional which makes null handling clearer for the client.
Here are two suggested options to get rid of if else repetitions one with loops another with streams:
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class CommandPatternExample {
private List<Command> candidates = Arrays.asList(new ACommand(), new BCommand(), new CCommand());
public Optional<Command> createCommand(String content) {
for(Command command : candidates) {
if(command.isMatching(content)) {
return Optional.of(command);
}
}
return Optional.empty();
}
public Optional<Command> createCommandStream(String content) {
return candidates.stream().filter(c -> c.isMatching(content)).findFirst();
}
}
interface Command<T> {
void execute(T obj);
boolean isMatching(String s);
}
class ACommand implements Command<String> {
#Override
public void execute(String obj) {
}
#Override
public boolean isMatching(String s) {
return "A".equals(s);
}
}
class BCommand implements Command<String> {
#Override
public void execute(String obj) {
}
#Override
public boolean isMatching(String s) {
return "B".equals(s);
}
}
class CCommand implements Command<String> {
#Override
public void execute(String obj) {
}
#Override
public boolean isMatching(String s) {
return "C".equals(s);
}
}
Map might be a good idea. Meaning if you place your command instances into a map as values where your key would be something that you could match against incoming String. Then instead of sequential search with Efficiency O(n) you can get much better performance O(1). This is a short answer.
Besides that There is an open source java library MgntUtils (wriiten by me) that contains some utility called "Self-instantiating factories" Basically it manages and the Factory for you. All you will need to do is to create a class that implements a certain interface and the utility will add it for you into a map based factory. It might be useful to you. Here is the link to an article that explains about the utilities in the library as well as where to get the library (Github and Maven central). In the article look for the paragraph "Lifecycle management (Self-instantiating factories)". Also library comes with a detailed written javadoc and code example for that feature.
I am currently working on a pretty simple project to improve my SOLID and Design Patterns Knowledge.
The idea was to create a "Smart Lock" for a door that can recognize a person by different parameters such as fingerprints, facial recognition, etc.
I immediately saw the potential in using the Strategy Design Pattern, and therefore I created a Lock interface and a Key abstract class:
public interface Lock {
boolean unlock(Key key);
}
public abstract class Key {
private String id;
public String getId(){
return (this.id);
}
}
I created two classes that will extend Key - FacePhoto and FingerPrint:
public class FacePhoto extends Key {
}
public class FingerPrint extends Key {
}
Then I created classes that implement Lock such as FingerPrintRecognizer and FacialRecognizer:
public class FacialRecognizer implements Lock {
#Override
public boolean unlock(Key key) throws Exception {
if(key instanceof FacePhoto){
//check validity
return true;
}
else {
throw new Exception("This key does not fit this lock");
}
}
}
public class FingerPrintRecognizer implements Lock {
#Override
public boolean unlock(Key key) throws Exception {
if(key instanceof FingerPrint){
//check validity
return true;
}
else {
throw new Exception("This key does not fit this lock");
}
}
}
I couldn't really find a better way to handle cases in which users of the Lock interface will try to open Locks with keys that don't fit.
Also, I had trouble with the "instanceof" if statement because it appears in every class that implements Lock.
Is Strategy a good practice in this case? if not, what would be a fine alternative (a different Design Pattern perhaps).
Strategy pattern provides the ability to change behavior at runtime. In your case a particular concrete implementation of Lock can work with specific implementation of key and thereby the logic does not allow the behavior change so the pattern is a misfit in current implementation.
Example for Strategy pattern.
class A{
private Behavior b; //behavior which is free to change
public void modifyBehavior(Behavior b){
this.b = b;
}
public void behave(){
b.behave(); // there is no constraint of a specific implementation but any implementation of Behavior is allowed.
}
}
class BX implements Behavior {
public void behave(){
//BX behavior
}
}
class BY implements Behavior {
public void behave(){
//BY behavior
}
}
interface Behavior {
void behave();
}
In your case you need to refactor the abstractions to better fit the logic.
As a refactoring (not using strategy pattern for current situation as forcing design pattern usuage is a bad practice, currently L from SOLID principles is being violated ) you can consider another answer to your question. https://stackoverflow.com/a/49763677/504133
A Lock can be opened using a specific type of Key
interface Lock<K extends Key> {
void unlockUsing(K key);
}
interface Key {
// TODO
}
A Door is composed of multiple Lock objects. Each Lock may require a different type of key. But you want to keep the interface "single-entry".
class Door {
private Lock<FacePhoto> faceLock;
private Lock<FingerPrint> printLock;
public void unlockUsing(Key key) {
// which lock to use?
}
}
We need some way to dispatch the key to the correct lock. If a FacePhoto is used for the Key, we want the faceLock to be used.
Currently, the Key is the only one who knows/decides which lock should be used. Why not allow the Key to decide which lock to use?
First, for the key to decide which lock to use, we need to somehow pass these locks to the key. We can hide the different locks behind a facade and pass that to Key:
class Door {
private LockSet locks;
public void unlockUsing(Key key) {
key.unlock(locks); // the key will decide!
}
}
interface Key {
void unlock(LockSet locks);
}
class LockSet {
private Lock<FacePhoto> faceLock;
private Lock<FingerPrint> printLock;
public void unlockUsing(FacePhoto photo) {
faceLock.unlockUsing(photo);
}
public void unlockUsing(FingerPrint print) {
printLock.unlockUsing(print);
}
}
Now to implement your keys:
class FacePhoto implements Key {
public void unlock(LockSet locks) {
locks.unlockUsing(this);
}
public boolean matches(FacePhoto photo) {
boolean matches = false;
// TODO: check if match
return matches;
}
}
class FingerPrint implements Key {
public void unlock(LockSet locks) {
locks.unlockUsing(this);
}
public boolean matches(FingerPrint print) {
// TODO: check if match
}
}
You can't use the wrong key with the wrong lock. All the potential locks are specified via LockSet. Since LockSet exposes a type-safe interface, you cannot try to open a Lock<FacePhoto> with a FingerPrint, the compiler won't let you (which is a good thing - catch mismatch errors before runtime). You cannot try to use unsupported keys either.
This design is called the visitor pattern. If there's something you disagree with, or need further explanation, please let me know.
In general, the Strategy Pattern is good when the relationship between two abstractions is one-to-many. For example, if you have one lock and many keys that can be used to open the lock. For example, the following would be a good case for the Strategy Pattern:
public class Lock {
public void unlock(Key key) {
// Unlock lock if possible
}
}
public interface Key {
public int someState();
}
public class FooKey implements Key {
#Override
public int someState() { ... }
}
public class BarKey implements Key {
#Override
public int someState() { ... }
}
What you have in your question is a many-to-many problem, with many locks that can be opened by a multiplicity of keys, where some keys can be used to open some locks and cannot open others. For this type of problem, the Visitor Pattern is a good choice, where the algorithm is the unlocking process and the object is the lock. The benefit of this approach is that the success or failure lock (whether a specific key unlocks a specific lock) is contained in simple methods without using instanceof.
In general, using instanceof signifies that some form of polymorphism is needed (i.e. instead of testing each supplied object to see if it is a certain type and executing logic based on that type, the type should have a polymorphic method whose behavior varies depending on the object type). This issue is so common, there is a standard refactoring to replace it: Replace Conditional with Polymorphism.
To implement the Visitor Pattern for your purposes, you can try something akin to the following:
public class UnlockFailedException extends Exception {
public UnlockFailedException(Lock lock, Key key) {
this("Key " + key.getClass().getSimpleName() + " failed to unlock lock " + lock.getClass().getSimpleName());
}
public UnlockFailedException(String message) {
super(message);
}
}
public interface Lock {
public void unlock(Key key);
}
public interface Key {
public void unlock(FacialRecognizer lock) throws UnlockFailedException;
public void unlock(FingerPrintRecognizer lock) throws UnlockFailedException;
}
public class FacialRecognizer implements Lock {
#Override
public void unlock(Key key) {
key.unlock(this);
}
}
public class FingerPrintRecognizer implements Lock {
#Override
public void unlock(Key key) {
key.unlock(this);
}
}
public class FacePhoto extends Key {
#Override
public void unlock(FacialRecognizer lock) throws UnlockFailedException {
// Unlock the lock
}
#Override
public void unlock(FingerPrintRecognizer lock) throws UnlockFailedException {
throw new UnlockFailedException(lock, this);
}
}
public class FingerPrint extends Key {
#Override
public void unlock(FacialRecognizer lock) throws UnlockFailedException {
throw new UnlockFailedException(lock, this);
}
#Override
public void unlock(FingerPrintRecognizer lock) throws UnlockFailedException {
// Unlock the lock
}
}
It may be tempting to group the unlock logic for each Lock into an abstract class (since it the same for every Lock implementation), but this would break the pattern. By passing this to the supplied Key, the compiler knows which overloaded method to call. This process is called double-dispatch. Although it may appear tedious, the logic of the call is simple (one line) and therefore, although there is repetition, it is not severe.
The drawback to this approach is that the Key interface must have an unlock method for each implementation of Lock. If one is lacking, the compiler will complain when the Lock implementation is made, since its unlock method will call unlock on Key, which does not contain a method that accepts the new Lock implementation. In that sense, the compiler acts as a check that ensures that a Key implementation can handle (either unlock or fail to unlock) each Lock implementation.
You can also implement a KeyRing that holds many Key objects can unlock a Lock using each of the Key objects until one is found that opens the Lock. If no Key is on the KeyRing that can open the Lock, a UnlockFailedException:
public class KeyRing {
public final List<Key> keys = new ArrayList<>();
public void addKey(Key key) {
keys.add(key);
}
public void removeKey(Key key) {
keys.remove(key);
}
public void unlock(Lock lock) throws UnlockFailedException {
for (Key key: keys) {
boolean unlockSucceeded = unlockWithKey(lock, key);
if (unlockSucceeded) return;
}
throw new UnlockFailedException("Could not open lock " + lock.getClass().getSimpleName() + " with key ring");
}
private boolean unlockWithKey(Lock lock, Key key) {
try {
lock.unlock(key);
return true;
}
catch (UnlockFailedException e) {
return false;
}
}
}
If the UnlockFailedException is too obtrusive, the unlock methods of Key can be changed to return a boolean that denotes if the unlock process succeeded. For example:
public interface Key {
public boolean unlock(FacialRecognizer lock);
public boolean unlock(FingerPrintRecognizer lock);
}
public class FacePhoto extends Key {
#Override
public boolean unlock(FacialRecognizer lock) {
// Unlock the lock
return true;
}
#Override
public boolean unlock(FingerPrintRecognizer lock) {
return false;
}
}
public class FingerPrint extends Key {
#Override
public void unlock(FacialRecognizer lock) {
return false;
}
#Override
public void unlock(FingerPrintRecognizer lock) {
// Unlock the lock
return true;
}
}
Using boolean return values also simplifies the implementation of the KeyRing:
public class KeyRing {
public final List<Key> keys = new ArrayList<>();
public void addKey(Key key) {
keys.add(key);
}
public void removeKey(Key key) {
keys.remove(key);
}
public boolean unlock(Lock lock) throws UnlockFailedException {
for (Key key: keys) {
boolean unlockSucceeded = lock.unlock(key);
if (unlockSucceeded) return true;
}
return false;
}
}
I have a if else statement which might grow in the near future.
public void decide(String someCondition){
if(someCondition.equals("conditionOne")){
//
someMethod("someParameter");
}else if(someCondition.equals("conditionTwo")){
//
someMethod("anotherParameter");
}
.
.
else{
someMethod("elseParameter");
}
}
Since, this is already looking messy, I think it would be better if I can apply any design patterns here. I looked into Strategy pattern but I am not sure if that will reduce if else condition here. Any suggestions?
This is a classic Replace Condition dispatcher with Command in the Refactoring to Patterns book.
Basically you make a Command object for each of the blocks of code in your old if/else group and then make a Map of those commands where the keys are your condition Strings
interface Handler{
void handle( myObject o);
}
Map<String, Handler> commandMap = new HashMap<>();
//feel free to factor these out to their own class or
//if using Java 8 use the new Lambda syntax
commandMap.put("conditionOne", new Handler(){
void handle(MyObject o){
//get desired parameters from MyObject and do stuff
}
});
...
Then instead of your if/else code it is instead:
commandMap.get(someCondition).handle(this);
Now if you need to later add new commands, you just add to the hash.
If you want to handle a default case, you can use the Null Object pattern to handle the case where a condition isn't in the Map.
Handler defaultHandler = ...
if(commandMap.containsKey(someCondition)){
commandMap.get(someCondition).handle(this);
}else{
defaultHandler.handle(this);
}
Let's assume that we have such code (which is the same as yours):
public void decide(String someCondition) {
if(someCondition.equals("conditionOne")) {
someMethod("someParameter");
}
else if(someCondition.equals("conditionTwo")) {
someMethod("anotherParameter");
}
else {
someMethod("elseParameter");
}
}
Assuming that you don't want to refactor other parts of the application and you don't want to change method signature there are possible ways in which it could be refactored:
Warning - You should use generic versions of mentioned patterns.
I showed non generic ones because it is easier to read them.
Strategy + Factory Method
We can use Strategy and Factory Method patterns. We also take advantage of polymorphism.
private final StrategyConditionFactory strategyConditionFactory = new StrategyConditionFactory();
public void decide(String someCondition) {
Strategy strategy = strategyConditionFactory.getStrategy(someCondition)
.orElseThrow(() -> new IllegalArgumentException("Wrong condition"));
strategy.apply();
}
It would be better to design it in a way that else condition is included in the factory, and developer calls it on purpose. In such case we throw exception when condition is not meet. Alternatively we could write it exactly as it was in question. If you want so instead of .orElseThrow(() -> new IllegalArgumentException("Wrong condition")); put .orElse(new ElseStrategy());
StrategyConditionFactory (factory method):
public class StrategyConditionFactory {
private Map<String, Strategy> conditions = new HashMap<>();
public StrategyConditionFactory() {
conditions.put("conditionOne", new ConditionOneStrategy());
conditions.put("conditionTwo", new ConditionTwoStrategy());
//It is better to call else condition on purpose than to have it in the conditional method
conditions.put("conditionElse", new ElseStrategy());
//...
}
public Optional<Strategy> getStrategy(String condition) {
return Optional.ofNullable(conditions.get(condition));
}
}
Strategy interface:
public interface Strategy {
void apply();
}
Implementations:
public class ConditionOneStrategy implements Strategy {
#Override
public void apply() {
//someMethod("someParameter");
}
}
public class ConditionTwoStrategy implements Strategy {
#Override
public void apply() {
//someMethod("anotherParameter")
}
}
public class ElseStrategy implements Strategy {
#Override
public void apply() {
//someMethod("elseParameter")
}
}
Usage (simplified):
public void strategyFactoryApp() {
//...
decide("conditionOne");
decide("conditionTwo");
decide("conditionElse");
//...
}
Strategy + Factory Method - this particular case (where only parameter changes)
We can use the fact that in this case we always call the same method, only parameter changes
We change our base strategy interface to abstract class with getParameter() method and we make new implementations of this abstract class. Other code remains the same.
public abstract class Strategy {
public abstract String getParameter();
public void apply() {
someMethod(getParameter());
}
private void someMethod(String parameter) {
//someAction
}
}
Implementations:
public class CondtionOneStrategy extends Strategy {
#Override
public String getParameter() {
return "someParameter";
}
}
public class CondtionTwoStrategy extends Strategy {
#Override
public String getParameter() {
return "anotherParameter";
}
}
public class ElseStrategy extends Strategy {
#Override
public String getParameter() {
return "elseParameter";
}
}
Enum + enum kinda "factory"
We might use Enum to implement strategy and instead of factory method we can use valueOf() from enum.
public void decide(String someCondition) {
ConditionEnum conditionEnum = ConditionEnum.valueOf(someCondition);
conditionEnum.apply();
}
Condition enum:
public enum ConditionEnum {
CONDITION_ONE {
#Override
public void apply() {
//someMethod("someParameter");
}
},
CONDITION_TWO {
#Override
public void apply() {
//someMethod("anotherParameter");
}
},
CONDITION_ELSE {
#Override
public void apply() {
//someMethod("elseParameter");
}
};
//...more conditions
public abstract void apply();
}
Usage (simplified):
public void enumFactoryApp() {
//...
decide("CONDITION_ONE");
decide("CONDITION_TWO");
decide("CONDITION_ELSE");
//...
}
Notice that you will get IllegalArgumentException when enum type has no constant with the specified name.
Command + Factory
The difference between strategy and command is that command holds also state, so if you have for example compute(int a, int b, String someCondition) and you want to refactor it with strategy including it's signature change you can reduce it to compute(int a, int b, ComputeStrategy computeStrategy) with command you can reduce it to one argument compute(ComputeCommand computeCommand). In this case we also take advantage of polymorphism similarly to strategy pattern case.
CommandConditionFactory commandConditionFactory = new CommandConditionFactory();
public void decide(String someCondition) {
Command command = commandConditionFactory.getCommand(someCondition)
.orElseThrow(() -> new IllegalArgumentException("Wrong condition"));
command.apply();
}
It would be better to design it in a way that else condition is included in the factory, and developer calls it on purpose. In such case we throw exception when condition is not meet. Alternatively we could write it exactly as it was in question. If you want so instead of .orElseThrow(() -> new IllegalArgumentException("Wrong condition")); put .orElse(new ElseCommand());
CommandConditionFactory (factory method):
public class CommandConditionFactory {
private Map<String, Command> conditions = new HashMap<>();
public CommandConditionFactory() {
conditions.put("conditionOne", new ConditionOneCommand("someParameter"));
conditions.put("conditionTwo", new ConditionTwoCommand("anotherParameter"));
//It is better to call else condition on purpose than to have it in the conditional method
conditions.put("conditionElse", new ElseCommand("elseParameter"));
//...
}
public Optional<Command> getCommand(String condition) {
return Optional.ofNullable(conditions.get(condition));
}
}
Command interface:
public interface Command {
void apply();
}
Implementations (there is some redundancy, but It is there to show how command should look in more general case where instead of someMethod() we have three different methods):
public class ConditionOneCommand implements Command {
private final String parameter;
public ConditionOneCommand(String parameter) {
this.parameter = parameter;
}
#Override
public void apply() {
//someMethod(parameter);
}
}
public class ConditionTwoCommand implements Command {
private final String parameter;
public ConditionTwoCommand(String parameter) {
this.parameter = parameter;
}
#Override
public void apply() {
//someMethod(parameter);
}
}
public class ElseCommand implements Command {
private final String parameter;
public ElseCommand(String parameter) {
this.parameter = parameter;
}
#Override
public void apply() {
//someMethod(parameter);
}
}
Usage (simplified):
public void commandFactoryApp() {
//...
decide("conditionOne");
decide("conditionTwo");
decide("conditionElse");
//...
}
Command + Factory - This particular case.
This in fact isn't a real command pattern just a derivative. It takes advantage of the fact that in this case we are always calling the same method someMethod(parameter) and only the parameter changes.
Abstract class:
public abstract class Command {
abstract void apply();
protected void someMethod(String parameter) {
//someAction
}
}
Implementation (the same for all 3 conditional cases):
public class CommandImpl extends Command {
private final String parameter;
public CommandImpl (String parameter) {
this.parameter = parameter;
}
#Override
public void apply(){
someMethod(parameter);
}
}
Factory, please notice that there is only one command implementation, only parameter changes:
public class CommandConditionFactory {
Map<String, Command> conditions = new HashMap<>();
public CommandConditionFactory() {
conditions.put("conditionOne", new CommandImpl("someParameter"));
conditions.put("conditionTwo", new CommandImpl("anotherParameter"));
//It is better to call else condition on purpose than to have it in the conditional method
conditions.put("conditionElse", new CommandImpl("elseParameter"));
//...
}
public Optional<Command> getCommand(String condition) {
return Optional.ofNullable(conditions.get(condition));
}
}
Nested if's
Note that even if you have nested ifs sometimes it is possible to refactor them and use one of the mentioned techniques.
Lets say that we have following code:
public void decide2(String someCondition, String nestedCondition) {
if(someCondition.equals("conditionOne")) {
if(nestedCondition.equals("nestedConditionOne")){
someLogic1();
}
else if(nestedCondition.equals("nestedConditionTwo")){
someLogic2();
}
}
else if(someCondition.equals("conditionTwo")) {
if(nestedCondition.equals("nestedConditionThree")){
someLogic3();
}
else if(nestedCondition.equals("nestedConditionFour")){
someLogic4();
}
}
}
You could refactor it using mathematical logic rules:
public void decide2(String someCondition, String nestedCondition) {
if(someCondition.equals("conditionOne")
&& nestedCondition.equals("nestedConditionOne")) {
someLogic1();
}
else if(someCondition.equals("conditionOne")
&& nestedCondition.equals("nestedConditionTwo")) {
someLogic2();
}
else if(someCondition.equals("conditionTwo")
&& nestedCondition.equals("nestedConditionThree")) {
someLogic3();
}
else if(someCondition.equals("conditionTwo")
&& nestedCondition.equals("nestedConditionFour")) {
someLogic4();
}
}
and then you can use strategy, enum or command. You just have a pair of Strings <String, String> instead of single String.
Decision Tables
When you have nested ifs that couldn't be refactored as mentioned you can implement your own decision tables or use some ready to go decision tables solution. I won't give the implementation there.
Rules Engine
When you have nested ifs that couldn't be refactored as mentioned you can also implement your own simple rules engine. You should use it only if you have many nested ifs, otherwise it is triumph of form over content.
For very complicated Business Logic there are professional Rule Engines like Drools.
I won't give the implementation there.
One more thing
In the example that you gave there is a high possibility that someone introduced these ifs, but they are totally redundant. And we can check it by trying to refactor decide method signature to make it take some other argument and to refactor surrounding code that is calling our method. By doing so we are getting rid of our Factory Method. There are examples that present how the code might look when it occurs that these ifs were redundant.
Strategy
Decide method:
public void decide(Strategy strategy) {
strategy.apply();
}
Usage (simplified):
public void strategyApp() {
//...
decide(new ConditionOneStrategy());
decide(new ConditionTwoStrategy());
decide(new ElseStrategy());
//...
}
Enum
Decide method:
public void decide(ConditionEnum conditionEnum) {
conditionEnum.apply();
}
Usage (simplified):
public void enumApp() {
//...
decide(ConditionEnum.CONDITION_ONE);
decide(ConditionEnum.CONDITION_TWO);
decide(ConditionEnum.CONDITION_ELSE);
//...
}
Command
Decide method:
public void decide(Command command) {
command.apply();
}
Usage (simplified):
public void commandApp() {
//...
decide(new ConditionOneCommand("someParameter"));
decide(new ConditionTwoCommand("anotherParameter"));
decide(new ElseCommand("elseParameter"));
//...
}
In fact it is quite specific case, there are cases in which for example we have to use simple type like String, because it comes from the external system or condition is based on integer from input so we can't refactor the code so easily.
The general recommendation by Martin Fowler is to
Replace Conditional with Polymorphism.
In terms of design patterns this would often be the Strategy Pattern
Replace Conditional Logic with Strategy.
If you have a small, finite set of conditions, I recommend to use an enum to implement the Strategy Pattern (provide an abstract method in the enum and override it for each constant).
public enum SomeCondition{
CONDITION_ONE{
public void someMethod(MyClass myClass){
//...
}
},
CONDITION_TWO{
public void someMethod(MyClass myClass){
}
}
public abstract void someMethod(MyClass myClass);
}
public class MyClass{
//...
public void decide(SomeCondition someCondition){
someCondition.someMethod(this);
}
}
If it's really just a parameter you want to pick, then you could define the enum like this instead:
public enum SomeCondition{
CONDITION_ONE("parameterOne"),
CONDITION_TWO("parameterTwo");
private final String parameter;
private SomeCondition(String parameter){
this.parameter = parameter;
}
public String getParameter(){
return parameter;
}
}
public class MyClass{
//...
public void decide(SomeCondition someCondition){
someMethod(someCondition.getParameter());
}
}
Another way to solve the current problem is to use Factory Pattern. This provides functionality to extract a factory method that returns an object of a given type and performs the operation based on the concrete object behavior.
public interface Operation {
String process(String a, String b);
}
The method takes two string as input and returns the result.
public class Concatenation implements Operation {
#Override
public String process(String a, String b) {
return a.concat(b);
}
}
public class Join implements Operation {
#Override
public String process(String a, String b) {
return String.join(", ", a, b);
}
}
And then we should define a factory class which returns instances of Operation based on the given operator:
public class OperatorFactory {
static Map<String, Operation> operationMap = new HashMap<>();
static {
operationMap.put("concatenation", new Concatenation());
operationMap.put("join", new Join());
// more operators
}
public static Optional<Operation> getOperation(String operator) {
return Optional.ofNullable(operationMap.get(operator));
}
}
And now we can use it:
public class SomeServiceClass {
public String processUsingFactory(String a, String b, String operationName) {
Operation operation = OperatorFactory
.getOperation(operationName)
.orElseThrow(() -> new IllegalArgumentException("Invalid Operation"));
return operation.process(a, b);
}
}
I guess you must have already considered it, but if you are using JDK 7 or above, you can switch on strings. That way your code can look cleaner than a bunch of if-else statements.
I am playing with functional programming and in particular with Functional Java. I have implemented with success my version of the IO Monad and I am writing IO actions for my core. It is basically serializing objects to Xml files (the object type extends the custom XmlWritable interface).
Unfortunately, in order to do that, an instance of OutputStream AND one instance of XmlSerializer needs to be created. The scope of the OutputStream is wider than XmlSerializer's, which means that the only way I can see to be able to correctly handle both lifecycles within my IO monad is to carry both of them with me in a tuple, closing OutputStream after having written using XmlSerializer.
This leads to heavy and ugly code (Java 6 is definitely not the best for this):
public abstract class IO<R> {
[...]
}
public class IOActions {
public final F<String, IO<OutputStream>> openFileFn() {
return new F<String, IO<OutputStream>>() {
#Override
public IO<OutputStream> f(String fileName) {
[...]
}
};
}
/* This will be partially applied, encoding will be fixed */
public static final F<OutputStream, IO<P2<OutputStream, XmlSerializer>>> initSerializer() {
return new F<OutputStream, IO<P2<OutputStream, XmlSerializer>>>() {
#Override
public IO<P2<OutputStream, XmlSerializer>> f(OutputStream os) {
XmlSerializer = new ...
[...]
}
};
}
/* This will be partially applied as well */
public static final F2<XmlWritable, P2<OutputStream, XmlSerializer>, IO<P2<OutputStream, XmlSerializer>>> writeObjectFn() {
return new F2<XmlWritable, P2<OutputStream, XmlSerializer>, IO<P2<OutputStream, XmlSerializer>>>() {
#Override
public IO<P2<OutputStream, XmlSerializer>> f(XmlWritable object, P2<OutputStream, XmlSerializer> p) {
[...]
}
};
}
Is there a more idiomatic why to handle my use case in functional programming?
Lurking, I discovered the State Monad...but I am kind of scared to see what it is going to happen if I apply a State Monad on top of a IO Monad in Functional Java.
I actually took great inspiration from Functional-Java's DB combinators to solve similar problems. I made my very own "XML combinators" (and more) from this pattern, so its worth learning.
You might find this discussion on google groups useful.
edit - replying to the comment:
follow the code:
notice how you start a new connection using the StateDb, see that you have a few options to start a connection, one that eventually commits, and one that eventually rollback. these are just two examples of things you can "carry" with the computation. Essentially, every computation that you bind (a plain modaic bind), could potentially carry information.
here is an example i gave in the discussion above:
DB<PreparedStatement> prepareStatement(final String sql) {
return new DB<PreparedStatement>() {
public PreparedStatement run(Connection c) throws SQLException {
return c.prepareStatement(sql);
}}}
// for a query that a reader might perform, i might have a function like this:
F<PreparedStatement, DB<ResultSet>> runStatement() {
public DB<ResultSet> f(final PreparedStatement s) {
return new DB<ResultSet>() {
public ResultSet run (Connection c) throws SQLException {
return s.executeQuery();
}}}
So in this example, you can pass extra information, namely the sql query as a parameter to the function that gets bound. you could just as well had more parameters to runStatement.
to put it all together, you get something like:
ResultSet rs = DbState.reader("conn-url").run(prepareStatement("select * from table").bind(runStatement());
Hope this helps!
Here is what I have come up with. Feedback is very appreciated.
I followed the answer above, taking inspiration from the linked discussion:
public class IOXml<T extends XmlWritable> implements DataWriter<T>{
private final XmlSerializer mXmlSerializer;
private final Option<String> mXmlEncoding;
private final IO<OutputStream> ioCreateStream;
private final F<OutputStream, IO<Unit>> ioCloseStream;
#Inject
IOXml(IO<OutputStream> createStream, F<OutputStream, IO<Unit>> closeStream, XmlSerializer xmlSerializer, Option<String> xmlEncoding) {
mXmlSerializer = xmlSerializer;
mXmlEncoding = xmlEncoding;
ioCreateStream = createStream;
ioCloseStream = closeStream;
}
/**
* Write a T object which is XmlWritable.
* #param osAndSer The tuple containing OutputStream and XmlSerializer.
* #param object The object to write.
* #return IO monad object.
*/
protected IO<Unit> writeObject(final T object) {
return new IO<Unit>() {
#Override
public Unit performIO() throws IOException {
object.writeXml(mXmlSerializer);
return Unit.unit();
}
};
}
protected final F<Unit, IO<Unit>> writeObjectFn(final T object) {
return new F<Unit, IO<Unit>>() {
#Override
public IO<Unit> f(Unit a) {
return writeObject(object);
}
};
}
/**
* Initialize the XmlSerializer before using it.
* #param os An OutputStream.
* #param encoding The encoding of the xml file.
* #return An IO action returning nothing.
*/
protected IO<Unit> initXml(final OutputStream os) {
return new IO<Unit>() {
#Override
public Unit performIO() throws IOException {
mXmlSerializer.setOutput(os, mXmlEncoding.toNull());
mXmlSerializer.startDocument(mXmlEncoding.toNull(), true);
return Unit.unit();
}
};
}
/**
* Close the XmlSerializer after.
* #return An IO action returning nothing.
*/
protected IO<Unit> closeXml() {
return new IO<Unit>() {
#Override
public Unit performIO() throws IOException {
mXmlSerializer.endDocument();
return Unit.unit();
}
};
}
protected final F<Unit, IO<Unit>> closeXmlFn() {
return new F<Unit, IO<Unit>>() {
#Override
public IO<Unit> f(Unit a) {
return closeXml();
}
};
}
#Override
public void close() throws IOException {
closeXml().performIO();
}
#Override
public void write(T object) {
throw new UnsupportedOperationException("Are you sure? IOXml is a functional class. Use the function returned by liftIO instead.");
}
/**
* Curried function to write XML objects, given the object itself and an OutputStream.
* #return The curried function.
*/
protected F<OutputStream, F<T, IO<Unit>>> writeFn() {
// returning the outer
return new F<OutputStream, F<T, IO<Unit>>>() {
#Override
public F<T, IO<Unit>> f(final OutputStream os) {
// Returning the inner
return new F<T, IO<Unit>>() {
#Override
public IO<Unit> f(T object) {
return initXml(os).bind(writeObjectFn(object)).bind(closeXmlFn());
}
};
}
};
}
#Override
public IO<Unit> writeIO(final T object) {
return IOImpl.bracket(ioCreateStream, // init
ioCloseStream, // close
Function.partialApply2(writeFn(), object)); // body
}
}
How do I create a class to capture commands with differing argument types?
To capture commands with similar argument types to operate a door object by swinging, e.g. (Swing, DoorNo, swingAngle), I'd create a class as follows;
class DoorCommand {
private String commandName;
private int doorNo;
private float swingAngle;
public DoorCommand (String cmdName, int doorNo, float swing angle) {
// set values here
}
// do all the setter and getter here
}
My question is, I need to enable and disable doors' lock by using (Lock, ENABLE/DISABLE) as argument. How do I accommodate this in my DoorCommand class? I want to be able to store DoorCommands in a list; List<DoorCommand> doorCommands = new ArrayList<DoorCommand>();
Why wouldn't you extract interface for door command, say IDoorCommand?
Then make DoorCommand from your example implement it (I'd change the name to more relevant actually, something like SwingDoorCommand).
Then add another command, implementing IDoorCommand, say DoorLockControlCommand that closes/opens lock, depending on constructor argument.
This way you'll be able to store both types of commands in List<IDoorCommand> and invoke them without need to know details if what command does.
Hope this answers your question.
You might want to check out the Command Pattern, it allows you to create each command as a subclass of a common interface and therefore store the commands in a list for historical or undo purposes. In your case:
// The basic interface for all door commands
public interface DoorCommand {
public void execute(Door door) throws CommandException;
}
// The Door class is the recipient for all commands
public class Door {
private List<Command> history = new ArrayList<Command>();
private int angle;
private boolean locked;
public void addCommandToHistory(Command command) {
history.add(command);
}
// Getters and setters.
}
// The command to open the door
public class OpenDoor implements DoorCommand {
public void execute(Door door) throws CommandException {
door.addCommandToHistory(this);
if (door.isLocked()) {
throw new CommandException("Door is locked, cannot open");
}
if (door.getAngle() < 90) {
door.setAngle(90);
}
}
}
// Another command, LockDoor
public class LockDoor implements DoorCommand {
public void execute(Door door) throws CommandException {
door.addCommandToHistory(this);
door.setLocked(true);
}
}
Then you can use the commands like this:
public void operateDoor() {
Door door = new Door();
new LockDoor().execute(door);
new OpenDoor().execute(door);
}
Alternatively, you can pass the Door object to commands using a constructor.
I am not sure if I understand your question right. It seems to me that your commands are just storing the information of the operation, they are not operating on the door, e.g. changing the door's instance variables etc., right? If you're willing to change this, you could use the Command Pattern. Perhaps that's already your plan. The command then had to consider the Door's state when executing.
Use a visitor pattern.
Your command has a method that accepts a Door and acts upon it.
You loop over your DoorCommand objects and send each one the Door, it does what it want to do.
This way your DoorCommand logic is separated from the Door and also you don't need one massive DoorCommand class to implement all possible commands.
Here is a simple example:
static class Door {
private final String name;
public Door(String name) {
this.name = name;
}
public void accept(final DoorVisitor visitor) {
visitor.visit(this);
}
#Override
public String toString() {
return name;
}
}
static interface DoorVisitor {
void visit(Door door);
}
static class SwingCommand implements DoorVisitor {
private final float swingAngle;
public SwingCommand(float swingAngle) {
this.swingAngle = swingAngle;
}
#Override
public void visit(Door door) {
System.out.printf("Swing door %s by %s%n", door, swingAngle);
}
}
static class LockCommand implements DoorVisitor {
private boolean locked;
public LockCommand(boolean locked) {
this.locked = locked;
}
#Override
public void visit(Door door) {
System.out.printf("Door %s is locked: %s%n", door, locked);
}
}
public static void main(String[] args) throws Exception {
final Door door = new Door("Front Door");
final List<DoorVisitor> commands = new LinkedList<>();
commands.add(new SwingCommand(0));
commands.add(new LockCommand(true));
for (final DoorVisitor c : commands) {
door.accept(c);
}
}
Use something like this using polymorphism.
public class DoorCommand {
private String cmdName;
private static List<DoorCommand> list;
static interface DoorCommandBase {
void doAction(Object... arg);
}
class SwingCommand implements DoorCommandBase {
void doAction(Object... arg) {
int doorNo;
float swingAngle;
cmdName = arg[0];
doorNo = arg[1];
swingAngle = arg[2];
// action to be performed
updateList(arg);
}
}
class LockCommand implements DoorCommandBase {
void doAction(Object... arg) {
boolean istrue;
cmdName = arg[0];
istrue = arg[1];
// action to be performed
updateList(arg);
}
}
public static void updateList(Object... arg) {
// update list
}
// getters and setters
}