There is an old, old ongoing debate about the best way to do dependency injection.
The original cut of spring instantiated a plain object, and then injected dependencies though setter methods.
But then a large contingency of folks insisted that injecting dependencies through constructor parameters was the correct way to do it.
Then, lately, as using reflection became more common, setting the values of private members directly, without setters or constructor args, became the rage.
So your first constructor is consistent with the second approach to dependency injection. It allows you to do nice things like inject mocks for testing.
But the no-argument constructor has this problem. Since it's instantiating the implementation classes for
DatabaseTransactionLog, it creates a hard, compile-time dependency on PayPal and the Database. It takes responsibility for building and configuring that entire dependency tree correctly.
Imagine that the PayPay processor is a really complicated subsystem, and additionally pulls in a lot of support libraries. By creating a compile-time dependency on that implementation class, you are creating an unbreakable link to that entire dependency tree. The complexity of your object graph has just jumped up by an order of magnitude, maybe two.
A lot of those items in the dependency tree will be transparent, but a lot of them will also need to be instantiated. Odds are, you won't be able to just instantiate a
In addition to instantiation, each of the objects will need properties applied from configuration.
If you only have a dependency on the interface, and allow an external factory to build and inject the dependency, they you chop off the entire PayPal dependency tree, and the complexity of your code stops at the interface.
There are other benefits, as being to specify implementations classes at in configuration (i.e. at runtime rather than compile time), or having more dynamic dependency specification that varies, say, by environment (test, integration, production).
For example, let's say that the PayPalProcessor had 3 dependent objects, and each of those dependencies had two more. And all those objects have to pull in properties from configuration. The code as-is would assume the responsibility of building all that out, setting properties from configuration, etc. etc. -- all concerns that the DI framework will take care of.
It may not seem obvious at first what you're shielding yourself from by using a DI framework, but it adds up and becomes painfully obvious over time. (lol I speak from the experience of having tried to do it the hard way)
In practice, even for a really tiny program, I find I end up writing in a DI style, and break up the classes into implementation / factory pairs. That is, if I'm not using a DI framework like Spring, I just throw together some simple factory classes.
That provides the separation of concerns so that my class can just do it's thing, and the factory class takes on the responsibility of building & configuring stuff.
Not a required approach, but FWIW
More generally, the DI / interface pattern reduces the complexity of your code by doing two things:
On top of that, since object instantiation and configuration is a pretty familiar task, the DI framework can achieve a lot of economies of scale through standardized notation & using tricks like reflection. Scattering those same concerns around classes ends up adding a lot more clutter than one would think.