I agree with @Zapadlo that this isn't too much of a problem given that the classes are cohesive. In a more general setting though, you may want to be more flexible with that kind of dependent computations.
In that case, you can look into traditional composition of functions to arrive at a more general abstraction:
Consider your first class B
(A
seems to init the chain by fetching the data initially). It takes data
as input, let's say of type T
. It does some side-effect and computes a new view of the data, called data2
in your code, of type S
. The same structure is present for C
. In terms of functions this is basically the Function<T, S>
composed with the Function<S, U>
.
Normally, a Function
should be side-effect free. In particular, when you enter the realm of functional programming. Depending on your and your team's affinity to this topic, you may just use a different name for the underlying interface altogether. Say, a DataHandler<T,S>
that takes data
of type T
, does something with it and return some updated data of type S
. It's basically the same thing though. (The name DataHandler
is not very good though). On the other hand, if you are familiar with FP, you can go take the fun route and rip out the side-effecting parts using monads.
Either way, abstracting the data-handling and -modification part into its own separate interface removes the direct dependencies between these classes. The underlying idea for this operation is the dependency inversion principle (DIP). The resulting caller code is then responsible for the actual composition, so there will be a single dedicated place in the code that creates the dependency chain B->C->D
, while the individual classes are not bothered by that chain.
Also, there is a good chance that after refactoring based on the DIP, you will find that the resulting code handling the data transformation and forwarding to a dependency looks very similar or even identical in the different classes. Then you can continue to refactor, following the Don't Repeat Yourself (DRY) principle if you feel it's worthwhile.