Skip to content

Instantly share code, notes, and snippets.

@UnquietCode
Last active December 19, 2015 03:29
Show Gist options
  • Save UnquietCode/5890203 to your computer and use it in GitHub Desktop.
Save UnquietCode/5890203 to your computer and use it in GitHub Desktop.
An encapsulation of the State Pattern in Java (http://en.wikipedia.org/wiki/State_pattern)
public interface ContextAware<T> {
void beforeMethod(AtomicReference<T> context);
}
public class Stateful {
/**
* This is a type-checking method, which gets around Java's inability
* to handle multiple bounds such as "V extends T & ContextAware<T>".
*
* @param value initial value, which should extends T
* @param contextAware initial value, which should extend ContextAware<T>
* @return a new proxy object
*/
public static <T> T getProxy(Class<T> clazz, T value, ContextAware<T> contextAware) {
if (value != contextAware) {
throw new IllegalArgumentException("This method expects the same object for both parameters.");
}
return getProxy(clazz, value);
}
@SuppressWarnings("unchecked")
private static <T> T getProxy(final Class<T> clazz, final Object initial) {
if (initial == null) {
throw new NullPointerException("needs a value to start");
}
return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
Object value = initial;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
AtomicReference<Object> ref = new AtomicReference<>(value);
((ContextAware) value).beforeMethod(ref);
Object retval = method.invoke(value, args);
value = ref.get();
return retval;
}
});
}
}
interface DoesStuff {
void doSomething(int i);
}
static class SomethingDoerA implements DoesStuff, ContextAware<DoesStuff> {
AtomicReference<DoesStuff> context;
@Override
public void beforeMethod(AtomicReference<DoesStuff> context) {
this.context = context;
}
@Override
public void doSomething(int i) {
System.out.println("hello "+i);
context.set(new SomethingDoerB());
}
}
static class SomethingDoerB implements DoesStuff, ContextAware<DoesStuff> {
AtomicReference<DoesStuff> context;
@Override
public void beforeMethod(AtomicReference<DoesStuff> context) {
this.context = context;
}
@Override
public void doSomething(int i) {
System.out.println("what's up "+(i+100));
context.set(new SomethingDoerA());
}
}
@Test
public void test() {
SomethingDoerA initial = new SomethingDoerA();
DoesStuff doer2 = StatefulX.getProxy(DoesStuff.class, initial, initial);
doer2.doSomething(1);
doer2.doSomething(2);
doer2.doSomething(3);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment