问题是创建现有对象的动态增强版本。
我无法修改的Class
。相反,我必须:
Class
要添加到现有对象的接口是:
public interface EnhancedNode {
Node getNode();
void setNode(Node node);
Set getRules();
void setRules(Set rules);
Map getGroups();
void setGroups(Map groups);
}
使用Byte Buddy,我设法继承了类并实现了我的接口。问题是委派给包装的对象。我发现做到这一点的唯一方法是使用反射速度太慢(我在应用程序上负担很重,性能至关重要)。
到目前为止,我的代码是:
Class<? extends Node> proxyType = new ByteBuddy()
.subclass(node.getClass(), ConstructorStrategy.Default.IMITATE_SUPER_TYPE_PUBLIC)
.method(anyOf(finalNode.getClass().getMethods())).intercept(MethodDelegation.to(NodeInterceptor.class))
.defineField("node", Node.class, Visibility.PRIVATE)
.implement(EnhancedNode.class).intercept(FieldAccessor.ofBeanProperty())
.defineField("groups", Map.class, Visibility.PRIVATE)
.implement(EnhancedNode.class).intercept(FieldAccessor.ofBeanProperty())
.defineField("rules", Set.class, Visibility.PRIVATE)
.implement(EnhancedNode.class).intercept(FieldAccessor.ofBeanProperty())
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
enhancedClass = (Class<N>) proxyType;
EnhancedNode enhancedNode = (EnhancedNode) enhancedClass.newInstance();
enhancedNode.setNode(node);
Node
子类/包装的对象在哪里。该NodeInterceptor
转发调用的方法的getNode
属性。
这里的代码NodeInterceptor
:
public class NodeInterceptor {
@RuntimeType
public static Object intercept(@Origin Method method,
@This EnhancedNode proxy,
@AllArguments Object[] arguments)
throws Exception {
Node node = proxy.getNode();
Object res;
if (node != null) {
res = method.invoke(method.getDeclaringClass().cast(node), arguments);
} else {
res = null;
}
return res;
}
}
一切正常,但拦截方法太慢,我打算直接使用ASM添加Node的每种方法的实现,但我希望有一种使用字节伙伴的更简单方法。
您可能想使用Pipe
而不是反射API:
public class NodeInterceptor {
@RuntimeType
public static Object intercept(@Pipe Function<Node, Object> pipe,
@FieldValue("node") Node proxy) throws Exception {
return proxy != null
? pipe.apply(proxy);
: null;
}
}
为了使用管道,首先需要安装它。如果您有可用的Java 8,则可以使用java.util.Function
。否则,只需定义某种类型:
interface Function<T, S> { S apply(T t); }
你自己 类型的名称和方法无关。安装类型:
MethodDelegation.to(NodeInterceptor.class)
.appendParameterBinder(Pipe.Binder.install(Function.class));
但是,您确定反射部分是应用程序性能问题的关键点吗?您是否正确缓存了生成的类,并且缓存有效地工作了?反射API比其声誉更快,尤其是因为使用字节伙伴倾向于隐含单态调用站点。
最后,一些一般性反馈。你在打电话
.implement(EnhancedNode.class).intercept(FieldAccessor.ofBeanProperty())
多次。这没有作用。另外,method.getDeclaringClass().cast(node)
没有必要。反射API为您执行转换。
我有一个小项目,用一个类包装另一个类的对象。修饰类实现了一个接口,但装饰类没有实现它。我很好奇它仍然是装饰模式还是其他模式,在我的项目中“装饰”类应该被称为包装器而不是装饰器。 我已经检查了iluwatar github存储库(https://github.com/iluwatar/java-design-patterns/tree/master/decorator/src/main/java/c
TypeScript 1.5现在有了装饰器。 有人能提供一个简单的例子来演示实现装饰器的正确方法,并描述可能有效的装饰器签名中的参数意味着什么吗? 此外,在实现decorator时,是否应该记住任何最佳实践注意事项?
问题内容: 考虑这个小例子: 哪个打印 为什么参数(应该是Test obj实例)没有作为第一个参数传递给装饰函数? 如果我手动进行操作,例如: 它按预期工作。但是,如果我必须事先知道某个函数是否装饰,它就破坏了装饰器的全部目的。这里的模式是什么,还是我误会了什么? 问题答案: tl; dr 您可以通过将类作为描述符并返回部分应用的函数来解决此问题,该函数从中应用对象作为参数之一,如下所示 实际问题
问题内容: 我想在Python中实现装饰器模式,我想知道是否有一种方法可以编写一个装饰器,该装饰器仅实现要修改的功能,而无需为所有转发给装饰对象的功能编写样板。像这样: 我想将呼叫自动转发到。有没有一种方法可以将所有未实现的函数调用转发给的通用方法? 问题答案: 您可以使用:
本文向大家介绍基于Python 装饰器装饰类中的方法实例,包括了基于Python 装饰器装饰类中的方法实例的使用技巧和注意事项,需要的朋友参考一下 title: Python 装饰器装饰类中的方法 comments: true date: 2017-04-17 20:44:31 tags: ['Python', 'Decorate'] category: ['Python'] --- 目前在中文网
问题内容: 举个例子: 我遇到的问题是,甚至在我调用要装饰的函数之前就调用了。 开始输出: 在这一点上,我什至没有调用过一个装饰过的函数。 我刚刚开始使用装饰器,所以也许我缺少了一些东西。 问题答案: 我相信python装饰器只是语法糖。 和…一样 如您所见,即使没有调用 bar 也将调用 foo 。这就是为什么您看到装饰器函数的输出的原因。对于您将装饰器应用到的每个函数,您的输出应只包含一行。