[英]Design Patterns, override a method without need to re compile / relink
We are building a product that needs to run on production environments. 我们正在构建一种需要在生产环境上运行的产品。 We need to modify some of the functionality of a existing library.
我们需要修改现有库的某些功能。 The existing library has class's and methods, we need to override 1 or more methods so that the caller uses our overriden methods instead of the original library.
现有库具有类和方法,我们需要重写1个或多个方法,以便调用者使用我们的重写方法而不是原始库。
OriginalLibrary 原始图书馆
package com.original.library ;
public class OriginalLibrary {
public int getValue() {
return 1 ;
}
public int getAnotherValue() {
return 1 ;
}
}
Original Client 原始客户
public class MyClient {
private OriginalLibraryClass originalLibraryObject ;
public MyClient () {
originalLibraryObject = new OriginalLibraryClass() ;
System.out.println(originalLibraryObject.getValue()) ;
System.out.println(originalLibraryObject.getAnotherValue()) ;
}
}
Output 输出量
1 1个
2 2
Now, I need to change getValue()
to return 3
, instead of 1
现在,我需要将
getValue()
更改为返回3
,而不是1
Needed Output 所需输出
3 3
2 2
package com.original.library.improved ;
public class OriginalLibrary extends com.original.library.OriginalLibrary {
public int getValue() {
return 3 ;
}
public int getAnotherValue() {
return super.getAnotherValue() ;
}
}
If I do the above, I need to tell my Original Client
to reorder and use my new com.original.library.improved
jar file before com.original.library
. 如果执行上述操作,则需要告诉我的
Original Client
重新排序,并在 com.original.library
之前使用新的com.original.library.improved
jar文件。
I am almost convinced that this is the most non intrusive way
to launch my improved services over and above the OriginalLibrary
. 我几乎确信,这是在
OriginalLibrary
之上启动我的改进服务的最non intrusive way
。 I would have preferred a solution where I need to tell the customer to just add my jar file, no need to recompile, relink your client code. 在需要告诉客户只需添加我的jar文件,无需重新编译,重新链接您的客户端代码的情况下,我会首选一个解决方案。
Similar (not same) questions on a google search here here 关于google搜索的类似(不同)问题,请点击 此处
java assist is excellent library for bytecode manipulation. Java助手是用于字节码操作的优秀库。 I have modified code below as per your sample code given, You have to explore javaassist more for your actual requirenment
我已根据您提供的示例代码在下面修改了代码,您必须根据实际需要更多地探索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());
Now output of getValue is 3 because I changed body of that method. 现在,由于我更改了该方法的主体,因此getValue的输出为3。
A couple of questions - 几个问题-
new OriginalLibrary()
, then you're pretty much stuck with creating a new subclass of OriginalLibrary
and then asking your client to use your new OriginalLibraryImproved
class. new OriginalLibrary()
,那么您就很难创建一个新的OriginalLibrary
子类,然后要求您的客户端使用新的OriginalLibraryImproved
类。 This is a common problem encountered in projects and is one reason why a library should not allow its clients to instantiate its classes directly using the new
operator. new
运算符直接实例化其类的原因之一。 OriginalLibrary
using a factory method provided by the library (say, OriginalLibrary.getInstance()
), you may want to check if there are any hooks into the factory that allow you to change the object being returned. OriginalLibrary.getInstance()
)实例化OriginalLibrary
,则可能要检查工厂中是否有任何挂钩可以允许您更改要返回的对象。 Do you have full control of the source code of the original library? 您完全控制原始库的源代码吗?
If yes, then you definitely should (and I cannot emphasize this strongly enough) provide factory methods for any class in the library that is instantiable. 如果是的话,那么您绝对应该(并且我不能足够强调这一点)为可实例化的库中的任何类提供工厂方法。 Doing this allows you to change the actual object being returned without modifying the client (as long as the returned object's class is a subclass of the return value from the factory method).
这样做允许您更改实际返回的对象而无需修改客户端(只要返回的对象的类是factory方法的返回值的子类)。
If not, then I suggest you do the following. 如果没有,那么建议您执行以下操作。
OriginalLibrary
(say, OriginalLibraryImproved
). OriginalLibrary
的子类(例如, OriginalLibraryImproved
)。 OriginalLibraryFactory
that has a static method named getInstance()
. OriginalLibraryFactory
的Factory类,该类具有一个名为getInstance()
的静态方法。 Write code to return an instance of OriginalLibraryImproved
from this method. OriginalLibraryImproved
的实例。 new OriginalLibrary()
with OriginalLibraryFactory.getInstance()
. new OriginalLibrary()
替换为OriginalLibraryFactory.getInstance()
。 Note that this approach will only involve adding an extra import for the factory class. OriginalLibrary
reference as before. OriginalLibrary
引用来引用返回的实例。 The advantage of this approach is that it gives you complete flexibility to change the implementation details of OriginalLibraryImproved
without affecting the client in anyway. 这种方法的优势在于,它为您提供了完全的灵活性,可以在不影响客户端的情况下更改
OriginalLibraryImproved
的实现细节。 You could also swap OriginalLibararyImproved
with a newer version like OriginalLibraryImprovedVer2
and the client will be oblivious to the fact that it is using a new class. 您还可以将
OriginalLibararyImproved
与较新的版本(例如OriginalLibraryImprovedVer2
交换,客户端将不会注意到它正在使用新类。 You'll just have to make sure that OriginalLibraryImprovedVer2
subclasses OriginalLibrary
. 您只需要确保
OriginalLibraryImprovedVer2
子类OriginalLibrary
。
An even more flexible approach is to use the Wrapper or Decorator pattern to avoid the pitfalls of inheritance. 更加灵活的方法是使用包装器或装饰器模式来避免继承的陷阱。 You can understand more about the Decorator pattern here .
您可以在此处了解更多有关Decorator模式的信息 。
In a nutshell, try to avoid forcing your clients to use new
and try to avoid inheritance unless you have very compelling reasons. 简而言之,除非有非常令人信服的理由,否则请尽量避免强迫客户使用
new
并避免继承。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.