Java中的装饰器

时间:2012-08-22 02:50:45

标签: java python annotations

我在Python中看到装饰器example

def makebold(fn):
    def wrapped():
        return "<b>" + fn() + "</b>"
    return wrapped

def makeitalic(fn):
    def wrapped():
        return "<i>" + fn() + "</i>"
    return wrapped

@makebold
@makeitalic
def hello():
    return "hello world"

print hello() ## returns <b><i>hello world</i></b>

并且对如何在Java中实现它感到好奇,所以我使用Decorator Design Pattern搜索并得到一些示例。

public class Main {

    public static void main(String[] args) {
        Wrapper word = new BoldWrapper(new ItalicWrapper());
        // display <b><i>hello world</i></b>
        System.out.println(word.make("Hello World"));
    }
}

public interface Wrapper {

    public String make(String str);

}

public class BoldWrapper implements Wrapper {

    private Wrapper wrapper;

    public BoldWrapper() {

    }

    public BoldWrapper(Wrapper wrapper) {
        this.wrapper = wrapper;
    }

    @Override
    public String make(String str) {
        if(wrapper != null) {
            str = wrapper.make(str);
        }

        return "<b>" + str + "</b>";
    }

}

public class ItalicWrapper implements Wrapper {

    private Wrapper wrapper;

    public ItalicWrapper() {

    }

    public ItalicWrapper(Wrapper wrapper) {
        this.wrapper = wrapper;
    }

    @Override
    public String make(String str) {
        if(wrapper != null) {
            str = wrapper.make(str);
        }

        return "<i>" + str + "</i>";
    }

}

如何使用像这样的Java Annotation这样的Python示例

public class Main {
    public static void main(String[] args) {
        @BoldWrapper
        @ItalicWrapper
        String str = "Hello World";
        // Display <b><i>Hello World</i></b>
    }
}

public @interface BoldWrapper {
    public void wrap() default "<b>" + str + "</b>";
}

public @interface ItalicWrapper {
    public void wrap() default "<i>" + str + "</i>";
}

当我尝试制作样本时遇到了一些问题,问题是我不知道如何将str方法中的main值传递给{{1} }}和BoldWrapper因此它可以连接如何返回它,因此ItalicWrapper方法可以显示已连接的结果

请告知我对注释的理解是否有问题。

5 个答案:

答案 0 :(得分:3)

如果你对使用注释做这种东西特别感兴趣(你不必真的):

这个例子应该让你开始:

public class AnnotationTest
{
    @Target( ElementType.METHOD )
    @Retention( RetentionPolicy.RUNTIME )
    public static @interface TagWrapper
    {
        public String[] value() default {};
    }

    public static interface TextFragment
    {
        public String getText();
    }

    public static class TagWrapperProcessor
    {
        public static String getWrapperTextFragment( TextFragment fragment )
        {
            try
            {
                Method getText = fragment.getClass().getMethod( "getText" );
                TagWrapper tagWrapper = getText.getAnnotation( TagWrapper.class );
                String formatString = "<%s>%s</%s>";
                String result = ( String ) getText.invoke( fragment );
                for ( String tag : tagWrapper.value() )
                {
                    result = String.format( formatString, tag, result, tag );
                }
                return result;
            }
            catch ( Exception e )
            {
                throw new RuntimeException( e );
            }
        }
    }

    public static class BoldItalicFragment implements TextFragment
    {

        private String _text;

        public BoldItalicFragment( String text )
        {
            _text = text;
        }

        @Override
        @TagWrapper(
        {
            "b", "i"
        } )
        public String getText()
        {
            return _text;
        }

    }

    @Test
    public void testStuff()
    {
        System.out.println( TagWrapperProcessor.getWrapperTextFragment( new BoldItalicFragment( "Hello, World!" ) ) ); // prints: <i><b>Hello, World!</b></i>
    }
}

答案 1 :(得分:1)

1)你引用的链接是一个很好的链接 - 它对于Java的“装饰模式”是正确的。当然,“设计模式”本身独立于任何特定的OO语言:

2)这是另一个好的链接:

在Java中,装饰器模式的经典示例是Java I / O Streams实现。

FileReader       frdr = new FileReader(filename);
LineNumberReader lrdr = new LineNumberReader(frdr);

4)所以是的,“装饰者模式”是这个问题的一个很好的候选者。

就个人而言,我更喜欢这种解决方案:

   String myHtml = 
     new BoldText (
       new ItalicText (
         new HtmlText ("See spot run")));

5)但是注释也是一种选择。例如:

答案 2 :(得分:0)

这很晚了,但我认为这可能会对其他人有所帮助。从具有Function接口的Java 8中,我们可以编写类似于python装饰器的代码:

Function<Function<String, String>, Function<String, String>> makebold = func -> input -> "<b>" + func.apply(input) + "</b>";
Function<Function<String, String>, Function<String, String>> makeitalic = func -> input -> "<i>" + func.apply(input) + "</i>";

Function<String, String> helloWorld = input -> "hello world";
        System.out.println(makebold.apply(makeitalic.apply(helloWorld)).apply("")); // <b><i>hello world</i></b>

答案 3 :(得分:0)

Python 装饰器很像 Java 注释,但原理却大不相同。

<块引用>

注释,一种元数据形式,提供有关程序的数据,该数据不属于程序本身。注解对它们注解的代码的操作没有直接影响。

但是您可以使用字节码增强处理类文件。我做了一个简单的项目来实现这种方法。它在构建后使用 javassist 处理类文件。它在类中搜索具有指定注释的方法。并添加用于在包装方法和原始方法之间调用的桥接方法。看起来像是在调用 bridgeMethod() -> wrapperMethod() -> originalMethod()。您可以参考https://github.com/eshizhan/funcwraps

答案 4 :(得分:-1)

虽然这并没有解决如何使用注释的问题,而是使用&#34;装饰设计&#34;,我建议你使用&#34;构建器设计&#34;如果它更适合你的需要(似乎是这样)。

快速使用示例:

public class BuilderPatternExample {

    public static void main(String args[]) {

        //Creating object using Builder pattern in java
        Cake whiteCake = new Cake.Builder()
                                 .sugar(1)
                                 .butter(0.5)
                                 .eggs(2)
                                 .vanilla(2)
                                 .flour(1.5)
                                 .bakingPowder(0.75)
                                 .milk(0.5)
                                 .build();

        //Cake is ready to eat :)
        System.out.println(whiteCake);
    }
}

<强>输出: 蛋糕{糖= 0.75,黄油= 0.5,鸡蛋= 2,香草= 2,面粉= 1.5,烘焙粉= 0.0,牛奶= 0.5,樱桃= 0}

有关完整实施和非常好的解释,请检查 http://javarevisited.blogspot.mx/2012/06/builder-design-pattern-in-java-example.html