Using strategy design pattern with an abstract parameter - java

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;
}
}

Related

Java synchronization depending on method parameter

how can I provide synchronization upon method parameter values?
All method calls using the 'same' parameter value A should be synchronized. A method call with a different parameter value e.g. B can access, even when calls with A are already waiting. The next concurrent call for B must wait also for the first B to be released.
My use case: I want to synchronize the access to JPA entities on ID level but want to avoid pessimistic locking because I need kind of a queue. The 'key' for locking is intended to be the entity ID - which is in fact of the type Java Long.
protected void entityLockedAccess(SomeEntity myEntity) {
//getId() returns different Long objects so the lock does not work
synchronized (myEntity.getId()) {
//the critical section ...
}
}
I read about lock objects but I am not sure how they would suit in my case.
On the top level I want to manage a specific REST call to my application which executes critical code.
Thanks,
Chris
As far as I understood you basically want a different, unique lock for each of your SomeEntity IDs.
You could realize this with a Map<Integer, Object>.
You simply map each ID to an object. Should there already be an object, you reuse it. This could look something like this:
static Map<Integer, Object> locks = new ConcurrentHashMap<>();
public static void main(String[] args)
{
int i1 = 1;
int i2 = 2;
foo(i1);
foo(i1);
foo(i2);
}
public static void foo(int o)
{
synchronized (locks.computeIfAbsent(o, k -> new Object()))
{
// computation
}
}
This will create 2 lock objects in the map as the object for i1 is reused in the second foo(i1) call.
Objects which are pooled and potentially reused should not be used for synchronization. If they are, it can cause unrelated threads to deadlock with unhelpful stacktraces.
Specifically, String literals, and boxed primitives such as Integers should NOT be used as lock objects because they are pooled and reused.
The story is even worse for Boolean objects because there are only two instances of Boolean, Boolean.TRUE and Boolean.FALSE and every class that uses a Boolean will be referring to one of the two.
I read about lock objects but I am not sure how they would suit in my
case. On the top level I want to manage a specific REST call to my
application which executes critical code.
You DB will take care for concurrent writes and other transactional issues.
All you need to do is use Transactions.
I would also recommend you to go through the classical problems (DIRTY READs NON Repeatable reads). You can also use Optimistic Locking for
The problem is that you simply should not synchronize on values (for example strings, or Integer objects).
Meaning: you would need to define some special EntityId class here, and of course, all "data" that uses the same ID would somehow need to be using the same EntityId object then.
private static final Set<Integer> lockedIds = new HashSet<>();
private void lock(Integer id) throws InterruptedException {
synchronized (lockedIds) {
while (!lockedIds.add(id)) {
lockedIds.wait();
}
}
}
private void unlock(Integer id) {
synchronized (lockedIds) {
lockedIds.remove(id);
lockedIds.notifyAll();
}
}
public void entityLockedAccess(SomeEntity myEntity) throws InterruptedException {
try {
lock(myEntity.getId());
//Put your code here.
//For different ids it is executed in parallel.
//For equal ids it is executed synchronously.
} finally {
unlock(myEntity.getId());
}
}
id can be not only an 'Integer' but any class with correctly overridden 'equals' and 'hashCode' methods.
try-finally - is very important - you must guarantee to unlock waiting threads after your operation even if your operation threw exception.
It will not work if your back-end is distributed across multiple servers/JVMs.
Just use this class:
(and the map will NOT increase in size over time)
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
public class SameKeySynchronizer<T> {
private final ConcurrentHashMap<T, Object> sameKeyTasks = new ConcurrentHashMap<>();
public void serializeSameKeys(T key, Consumer<T> keyConsumer) {
// This map will never be filled (because function returns null), it is only used for synchronization purposes for the same key
sameKeyTasks.computeIfAbsent(key, inputArgumentKey -> acceptReturningNull(inputArgumentKey, keyConsumer));
}
private Object acceptReturningNull(T inputArgumentKey, Consumer<T> keyConsumer) {
keyConsumer.accept(inputArgumentKey);
return null;
}
}
Like in this test:
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class SameKeySynchronizerTest {
private static final boolean SHOW_FAILING_TEST = false;
#Test
void sameKeysAreNotExecutedParallel() throws InterruptedException {
TestService testService = new TestService();
TestServiceThread testServiceThread1 = new TestServiceThread(testService, "a");
TestServiceThread testServiceThread2 = new TestServiceThread(testService, "a");
testServiceThread1.start();
testServiceThread2.start();
testServiceThread1.join();
testServiceThread2.join();
Assertions.assertFalse(testService.sameKeyInProgressSimultaneously);
}
#Test
void differentKeysAreExecutedParallel() throws InterruptedException {
TestService testService = new TestService();
TestServiceThread testServiceThread1 = new TestServiceThread(testService, "a");
TestServiceThread testServiceThread2 = new TestServiceThread(testService, "b");
testServiceThread1.start();
testServiceThread2.start();
testServiceThread1.join();
testServiceThread2.join();
Assertions.assertFalse(testService.sameKeyInProgressSimultaneously);
Assertions.assertTrue(testService.differentKeysInProgressSimultaneously);
}
private class TestServiceThread extends Thread {
TestService testService;
String key;
TestServiceThread(TestService testService, String key) {
this.testService = testService;
this.key = key;
}
#Override
public void run() {
testService.process(key);
}
}
private class TestService {
private final SameKeySynchronizer<String> sameKeySynchronizer = new SameKeySynchronizer<>();
private Set<String> keysInProgress = ConcurrentHashMap.newKeySet();
private boolean sameKeyInProgressSimultaneously = false;
private boolean differentKeysInProgressSimultaneously = false;
void process(String key) {
if (SHOW_FAILING_TEST) {
processInternal(key);
} else {
sameKeySynchronizer.serializeSameKeys(key, inputArgumentKey -> processInternal(inputArgumentKey));
}
}
#SuppressWarnings("MagicNumber")
private void processInternal(String key) {
try {
boolean keyInProgress = !keysInProgress.add(key);
if (keyInProgress) {
sameKeyInProgressSimultaneously = true;
}
try {
int sleepTimeInMillis = 100;
for (long elapsedTimeInMillis = 0; elapsedTimeInMillis < 1000; elapsedTimeInMillis += sleepTimeInMillis) {
Thread.sleep(sleepTimeInMillis);
if (keysInProgress.size() > 1) {
differentKeysInProgressSimultaneously = true;
}
}
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
} finally {
keysInProgress.remove(key);
}
}
}
}

How is this "container Design Pattern" called?

While creating my app. architecture I faced the need for one structure, that will be described below.
I'm pretty sure, that there is a well known design pattern with the same functionality, because I think that problem, for which I develop it is really common.
I write my own implementation of this, but I always try to use "build in language" implementations of patterns, so - please help me to name this construction.
The idea is close to reader-writer pattern. We have a "container" in which we can add Objects by the key (). And also we can get this objects by keys, removing it from container.
So, the implemented class should have two methods:
void putObject(Key key, Object object);
Object getObject(Key key); // remove <Key,Object> from container.
The next is most interesting.
This container should work in multi-threading environment as follows:
If there is no object associated with key, while calling get(Key
key) method the caller thread should WAIT for the object in this
container.
When another thread will call putObject(Key key, Object object)
method it should check if there is some thread that wait exactly for
this object, and if it is - then signal and wake up the thread that
waits.
I think that it is common structure, does it have "official" name?
My Java implementation of this pattern:
private static interface BlackBox {
public void addObject(IdObject object);
public IdObject getObject(ObjectId id);
}
private static class BlackBoxImpl implements BlackBox {
private final Lock conditionLock = new ReentrantLock();
private final Map<ObjectId, IdObject> savedObjects;
private final Map<ObjectId, Condition> waitingConditions;
public BlackBoxImpl() {
this.savedObjects = new ConcurrentHashMap<ObjectId, IdObject>(20);
this.waitingConditions = new ConcurrentHashMap<ObjectId, Condition>(20);
}
#Override
public void addObject(IdObject object) {
savedObjects.put(object.getId(), object);
if (waitingConditions.containsKey(object.getId())) {
Condition waitCondition = waitingConditions.get(object.getId());
conditionLock.lock();
waitCondition.signal();
conditionLock.unlock();
}
}
#Override
public IdObject getObject(ObjectId id) {
if (savedObjects.containsKey(id)) {
return savedObjects.get(id);
} else {
conditionLock.lock();
Condition waitCondition = conditionLock.newCondition();
waitingConditions.put(id, waitCondition);
waitCondition.awaitUninterruptibly();
conditionLock.unlock();
return savedObjects.get(id);
}
}
}
private static interface IdObject {
public ObjectId getId();
}
private static class IdObjectImpl implements IdObject {
protected final ObjectId id;
public IdObjectImpl(ObjectId id) {
this.id = id;
}
#Override
public ObjectId getId() {
return id;
}
}
private static interface ObjectId {
}
private static class ObjectIdImpl implements ObjectId {
}
I would probably use something like a
ConcurrentMap<K,BlockingQue<V>>.
Use the concurrent methods of the Map to add the pair. Take from your queue for the value. Use an ArrayBlockingQue(1).
Something like this perhaps:
static class MultiQueue<K, V> {
// The base structure.
final ConcurrentMap<K, BlockingQueue<V>> queues = new ConcurrentHashMap<>();
/**
* Put an item in the structure.
*
* The entry in the map will be created if no entry is currently there.
*
* The value will then be posted to the queue.
*/
public void put(K k, V v) throws InterruptedException {
// Make it if not present.
ensurePresence(k).put(v);
}
/**
* Get an item from the structure.
*
* The entry in the map will be created if no entry is currently there.
*
* The value will then be taken from the queue.
*/
public void get(K k) throws InterruptedException {
// Make it if not present - and wait for it.
ensurePresence(k).take();
}
private BlockingQueue<V> ensurePresence(K k) {
// Make it if not present.
return queues.computeIfAbsent(k, v -> new ArrayBlockingQueue(1));
}
}
Looking at your design, to me what you are describing
We have a "container" in which we can add Objects by the key (). And also we can get this objects by keys, removing it from container.
This container should work in multi-threading environment
is close to concurrent Object pool. It uses a set of initialized objects kept ready to use. A client of the pool will request an object from the pool and perform operations on the returned object.
The only real difference I see is that you are getting the objects based on your own criteria.

Replacing if else statement with pattern

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.

Help with understanding a function object or functor in Java

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);
}

A thread-safe holder for arbitrary cloneable data

I have a class SomeMutableData with a public clone() method. I want to make sure, that no thread ever sees an inconsistent state (assuming the instances will be passed around using the holder only). I assume using synchronization is the safest possibility, right?
public final class ThreadSafeHolder {
public ThreadSafeHolder(SomeMutableData data) {
storeData(data);
}
public synchronized SomeMutableData cloneData() {
return data.clone();
}
public synchronized void storeData(SomeMutableData data) {
this.data = data.clone();
}
private SomeMutableData data;
}
Is the following as safe as the first approach?
public final class ThreadSafeHolder2 {
public ThreadSafeHolder2(SomeMutableData data) {
storeData(data);
}
public SomeMutableData cloneData() {
return data.get().clone();
}
public void storeData(SomeMutableData data) {
this.data.set(data.clone());
}
private final AtomicReference<SomeMutableData> data
= new AtomicReference<SomeMutableData>();
}
Since clone() is much more expensive than synchronized, it hardly matters from a performance point of view.
However the second example is as thread safe and marginally faster.
the only differences is that the first example you can do this. (Whether you like this or not ;)
synchronized(theHolder) {
SomeMutableData smd = theHolder.cloneData();
smd.updateIt();
theHolder.storeData(smd);
}
BTW: I don't think the holder should extend the type it is wrapping.
EDIT: A more GC friendly way is to use the following approach. you can write copyFrom() such that no objects are created either setting or getting the data.
public final class ThreadSafeHolder {
private final SomeMutableData data = new SomeMutableData();
public ThreadSafeHolder(SomeMutableData data) {
copyFrom(data);
}
public synchronized void copyTo(SomeMutableData data) {
data.copyFrom(this.data);
}
public synchronized void copyFrom(SomeMutableData data) {
this.data.copyFrom(data);
}
}

Categories