有没有一种优雅的方法可以使类中的每个方法都以一定的代码块开头?

有没有一种优雅的方法可以使类中的每个方法都以一定的代码块开头?,第1张

有没有一种优雅的方法可以使类中的每个方法都以一定的代码块开头?

我对优雅并不了解,但这是一个使用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个烦恼,我承认,我对自己不满意:

  1. 调用处理程序使用魔术字符串跳过“ getEnabled”和“ setEnabled”方法上的“ enabled-check”。如果重构了方法名称,这很容易中断。
  2. 如果存在需要添加不应继承“ 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);        }    }}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5565048.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存