我对优雅并不了解,但这是一个使用Java内置函数的有效实现,
java.lang.reflect.Proxy该实现 强制
所有方法调用均
Foo始于检查
enabled状态。
main方法:
public static void main(String[] args) { Foo foo = Foo.newFoo(); foo.setEnabled(false); foo.bar(); // won't print anything. foo.setEnabled(true); foo.bar(); // prints "Executing method bar"}
Foo接口:
public interface Foo { boolean getEnabled(); void setEnabled(boolean enable); void bar(); void baz(); void bat(); // Needs Java 8 to have this convenience method here. static Foo newFoo() { FooFactory fooFactory = new FooFactory(); return fooFactory.makeFoo(); }}
FooFactory类:
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class FooFactory { public Foo makeFoo() { return (Foo) Proxy.newProxyInstance( this.getClass().getClassLoader(), new Class[]{Foo.class}, new FooInvocationHandler(new FooImpl())); } private static class FooImpl implements Foo { private boolean enabled = false; @Override public boolean getEnabled() { return this.enabled; } @Override public void setEnabled(boolean enable) { this.enabled = enable; } @Override public void bar() { System.out.println("Executing method bar"); } @Override public void baz() { System.out.println("Executing method baz"); } @Override public void bat() { System.out.println("Executing method bat"); } } private static class FooInvocationHandler implements InvocationHandler { private FooImpl fooImpl; public FooInvocationHandler(FooImpl fooImpl) { this.fooImpl = fooImpl; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getDeclaringClass() == Foo.class && !method.getName().equals("getEnabled") && !method.getName().equals("setEnabled")) { if (!this.fooImpl.getEnabled()) { return null; } } return method.invoke(this.fooImpl, args); } }}
正如其他人指出的那样,如果您只需要考虑几种方法,这似乎对您所需的东西就算是过大了。
也就是说,肯定有好处:
- 实现了某种关注点分离,因为
Foo
的方法实现不必担心enabled
检查跨领域关注点。相反,该方法的代码只需要担心该方法的主要目的是什么,仅此而已。 - 无辜的开发人员无法将新方法添加到
Foo
类中并错误地“忘记”添加enabled
检查。该enabled
检查的行为由新添加的方法自动继承。 - 如果您需要添加另一个横切关注点,或者需要增强
enabled
检查效果,那么在一个地方安全,轻松地进行检查非常容易。 - 可以通过内置的Java功能获得类似AOP的行为,这是一种很好的选择。您不必被迫集成诸如之类的其他框架
Spring
,尽管它们也绝对是不错的选择。
公平地说,一些缺点是:
- 一些处理代理调用的实现代码很丑陋。有人还会说拥有内部类来防止类的实例化
FooImpl
是丑陋的。 - 如果要向中添加新方法
Foo
,则必须在两个位置进行更改:实现类和接口。没什么大不了的,但是还有很多工作要做。 - 代理调用不是免费的。有一定的性能开销。对于一般用途,它不会引起注意。
编辑:
Fabian Streitel的评论使我想出了上述解决方案中的2个烦恼,我承认,我对自己不满意:
- 调用处理程序使用魔术字符串跳过“ getEnabled”和“ setEnabled”方法上的“ enabled-check”。如果重构了方法名称,这很容易中断。
- 如果存在需要添加不应继承“ enabled-check”行为的新方法的情况,那么开发人员很容易会出错,至少,这意味着添加更多的魔术。字符串。
要解决第1点,并至少缓解第2点的问题,我将创建一个注释
BypassCheck(或类似的注释),该注释可用于标记
Foo我不想为其执行“启用检查”。这样,我根本不需要魔术字符串,在这种特殊情况下,开发人员正确添加新方法变得容易得多。
使用注释解决方案,代码如下所示:
main方法:
public static void main(String[] args) { Foo foo = Foo.newFoo(); foo.setEnabled(false); foo.bar(); // won't print anything. foo.setEnabled(true); foo.bar(); // prints "Executing method bar"}
BypassCheck注解:
import java.lang.annotation.*;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface BypassCheck {}
Foo接口:
public interface Foo { @BypassCheck boolean getEnabled(); @BypassCheck void setEnabled(boolean enable); void bar(); void baz(); void bat(); // Needs Java 8 to have this convenience method here. static Foo newFoo() { FooFactory fooFactory = new FooFactory(); return fooFactory.makeFoo(); }}
FooFactory类:
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class FooFactory { public Foo makeFoo() { return (Foo) Proxy.newProxyInstance( this.getClass().getClassLoader(), new Class[]{Foo.class}, new FooInvocationHandler(new FooImpl())); } private static class FooImpl implements Foo { private boolean enabled = false; @Override public boolean getEnabled() { return this.enabled; } @Override public void setEnabled(boolean enable) { this.enabled = enable; } @Override public void bar() { System.out.println("Executing method bar"); } @Override public void baz() { System.out.println("Executing method baz"); } @Override public void bat() { System.out.println("Executing method bat"); } } private static class FooInvocationHandler implements InvocationHandler { private FooImpl fooImpl; public FooInvocationHandler(FooImpl fooImpl) { this.fooImpl = fooImpl; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getDeclaringClass() == Foo.class && !method.isAnnotationPresent(BypassCheck.class) // no magic strings && !this.fooImpl.getEnabled()) { return null; } return method.invoke(this.fooImpl, args); } }}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)