Continued from the previous page./xo0M0) and then expand on it.
The above says: "Programming based on abstract interfaces is indeed a best practice: exposing easily changeable points of functionality by defining abstract interfaces, and isolating and extending different implementations, which embodies the principle of openness and closure"
However, in real projects, which are often developed in collaboration with many people, some historical reasons lead to the implementation of certain code snippets tend to be "strange", which can't be well covered unilaterally, and at the same time is also filled with "bad code flavor" that violates the principle of opening and closing;
You, as the "chosen one", need to iterate on its functionality;
Maybe after your assessment, go for a radical architectural evolution, which is kudos;
But sometimes it's also a matter of global ROI to assess whether the benefits of a radical reorganization are large enough, and sometimes we have to compromise (trade-off). I.e., how to do a relatively good refactoring within a tight delivery cycle and not let the code continue to decay;
So this time, we continue with the two arts of modifying code:Methods addedcap (a poem)method override
Strategy 1: Methodological additions
Isolate old logic by adding new methods, i.e., cut "gaps" in old methods and inject new business logic to be called;
Take the previous case, for example, an old historical method.Need to filter out empty objects from the returned data set:
The logic here is simple, using theJava Lambda The expression does the filtering, but the way it's written certainly adds insult to injury: indeed the original method was already very Low and couldn't be unilateral. This time, I just added a simple piece of logic at the end. It's already familiar, and probably quite a lot of people will mess with it this way;
But as a good programmer, the immediate status quo indeed we can only compromise, but the follow-up of each line of code, the need to do quality and quantity, and strive to do without affecting the original business logic to do testable;
"Methods added": by adding new methodsgetDataIfNotNull to isolate the old logic:
as belowgetDataIfNotNull As an added method, it is easy to test it independently, while the original methoddoSomething And it didn't continue to corrupt.
You can see that the advantages are obvious: clear isolation of old and new code; and of course, for more segregation of duties, the use of theNew class segregationIt'll be better;
Strategy 2: Method Overrides
Rename the method to be modified, create a new method with the same name and signature as the original method, and call the renamed original method in the new method;
Assuming a new demand: fordoSomething method does a message notification operation, then "method override" that is:
Combining the original methodologydoSomething renamedoSomethingAndFilterDataand then create a new method with the same name as the original method.doSomething, and finally call the renamed original method in the new method:
Another way to write method overrides: usually a new method is defined, and then the old and new business logic is invoked sequentially in the new method;
Typically used to cut stream old and new logic as the architecture evolves; e.g., based on client version, greater than3. The client-side tangential flow uses the new logic - we create a new method calling both the old and new methods.
The benefits of this are obvious: no changes are made to the old approach, and the flow is cut at a higher "upper" level: new functionality is guaranteed to evolve iteratively, while the old functionality remains unchanged.
You can see that "method override" regardless of how it is implemented, it does not add logic to the current old method, but by using the new method as an entry point, so as to avoid coupling the old and new logic together;
"Method overriding can be taken a step further by using a separate class to isolate it, known as the decorator pattern. Often the original class is so complex that you don't want to iterate on it anymore, so consider decoupling it with a decorator:
class DecoratedFoo extends Foo{