Java 设计模式,重写方法而无需重新编译/重新链接
我们正在构建一种需要在生产环境中运行的产品。我们需要修改现有库的一些功能。现有库具有类和方法,我们需要重写1个或多个方法,以便调用方使用我们重写的方法而不是原始库 原始图书馆Java 设计模式,重写方法而无需重新编译/重新链接,java,design-patterns,Java,Design Patterns,我们正在构建一种需要在生产环境中运行的产品。我们需要修改现有库的一些功能。现有库具有类和方法,我们需要重写1个或多个方法,以便调用方使用我们重写的方法而不是原始库 原始图书馆 package com.original.library ; public class OriginalLibrary { public int getValue() { return 1 ; } public int getAnotherValue() { retu
package com.original.library ;
public class OriginalLibrary {
public int getValue() {
return 1 ;
}
public int getAnotherValue() {
return 1 ;
}
}
原始客户
public class MyClient {
private OriginalLibraryClass originalLibraryObject ;
public MyClient () {
originalLibraryObject = new OriginalLibraryClass() ;
System.out.println(originalLibraryObject.getValue()) ;
System.out.println(originalLibraryObject.getAnotherValue()) ;
}
}
输出
一,
二,
现在,我需要更改getValue()
以返回3
,而不是1
所需输出
三,
二,
如果我做了上述操作,我需要告诉我的原始客户端
在com.Original.library
之前重新排序并使用我新的com.Original.library.改良的
jar文件
我几乎确信,这是在原始库
之上推出改进服务的最非侵入式方式。我更喜欢一个解决方案,我需要告诉客户只添加我的jar文件,不需要重新编译,重新链接您的客户机代码
谷歌搜索中的类似(不相同)问题
java assist是字节码操作的优秀库。我已经根据您给出的示例代码修改了下面的代码,您必须根据您的实际需求进一步探索javaassist
CtClass etype = ClassPool.getDefault().get("com.original.library.OriginalLibrary");
// get method from class
CtMethod cm = etype.getDeclaredMethod("getValue");
// change the method bosy
cm.setBody("return 3;");
etype.rebuildClassFile();
// give the path where classes is placed, In my eclipse it is bin
etype.writeFile("bin");
OriginalLibrary originalLibraryObject;
originalLibraryObject = new OriginalLibrary();
System.out.println(originalLibraryObject.getValue());
System.out.println(originalLibraryObject.getAnotherValue());
现在getValue的输出是3,因为我更改了该方法的主体。java assist是字节码操作的优秀库。我已经根据您给出的示例代码修改了下面的代码,您必须根据您的实际需求进一步探索javaassist
CtClass etype = ClassPool.getDefault().get("com.original.library.OriginalLibrary");
// get method from class
CtMethod cm = etype.getDeclaredMethod("getValue");
// change the method bosy
cm.setBody("return 3;");
etype.rebuildClassFile();
// give the path where classes is placed, In my eclipse it is bin
etype.writeFile("bin");
OriginalLibrary originalLibraryObject;
originalLibraryObject = new OriginalLibrary();
System.out.println(originalLibraryObject.getValue());
System.out.println(originalLibraryObject.getAnotherValue());
现在getValue的输出是3,因为我更改了该方法的主体。有几个问题-
- 客户端如何获取库类的实例?
如果他们使用的是new OriginalLibrary()
,那么您就必须创建OriginalLibrary
的新子类,然后要求您的客户使用新的OriginalLibrary改进的
类。这是项目中遇到的常见问题,也是库不允许其客户端直接使用new
操作符实例化其类的原因之一。
相反,如果您的客户端正在使用库提供的工厂方法(例如,OriginalLibrary.getInstance()
)实例化OriginalLibrary
),则可能需要检查工厂中是否有允许您更改返回对象的挂钩李>
- 您是否完全控制原始库的源代码?
如果是的话,那么您肯定应该为库中任何可实例化的类提供工厂方法(我再怎么强调也不为过)。这样做可以在不修改客户端的情况下更改返回的实际对象(只要返回对象的类是factory方法返回值的子类)。
如果没有,那么我建议你做以下事情
- 创建
OriginalLibrary
的子类(例如,OriginalLibraryImproved
)
- 创建一个名为
OriginalLibraryFactory
的工厂类,它有一个名为getInstance()
的静态方法。编写代码以返回此方法改进的originallibrarymproved
的实例
- 请您的客户端将所有出现的
new OriginalLibrary()
替换为OriginalLibraryFactory.getInstance()
。请注意,这种方法只涉及为factory类添加额外的导入。客户端仍将使用与以前相同的原始库
引用来引用返回的实例李>
这种方法的优点是,它使您能够完全灵活地更改originallibrarymproved
的实现细节,而不会影响客户端。您还可以将originallibrarymproved
与更新的版本(如originallibrarymprovedver2
)进行交换,这样客户机就不会注意到它正在使用一个新类。您只需确保originallibrarymprovedver2
子类OriginalLibrary
更灵活的方法是使用包装器或装饰器模式来避免继承的陷阱。您可以进一步了解装饰图案
简而言之,除非你有非常令人信服的理由,否则尽量避免强迫你的客户使用new
,并尽量避免继承 有几个问题-
- 客户端如何获取库类的实例?
如果他们使用的是new OriginalLibrary()
,那么您就必须创建OriginalLibrary
的新子类,然后要求您的客户使用新的OriginalLibrary改进的
类。这是项目中遇到的常见问题,也是库不允许其客户端直接使用new
操作符实例化其类的原因之一。
相反,如果您的客户端正在使用库提供的工厂方法(例如,OriginalLibrary.getInstance()
)实例化OriginalLibrary
),则可能需要检查工厂中是否有允许您更改返回对象的挂钩李>
- 您是否完全控制原始库的源代码?
如果是的话,那么您肯定应该为库中任何可实例化的类提供工厂方法(我再怎么强调也不为过)。这样做可以在不修改客户端的情况下更改返回的实际对象(只要返回对象的类是factory方法返回值的子类)。
如果没有,那么我建议你做以下事情
- 创建
OriginalLibrary的子类