I suggest you try writing the same section of code both ways.
At first it looks fine, just which class do you want your method on
program_ADM
{
var service = new service(dep1,dep2)
var o = new obj()
var result = service.Calc(o)
}
vs
program_OOP
{
var o = new obj(dep1,dep2)
var result = o.Calc()
}
The difference starts to show itself when you have more than one operation
program_ADM
{
var serviceA = new service(dep1,dep2)
var serviceB = new service(dep3,dep4)
var o = new obj()
var resultA = serviceA.Calc(o)
var resultB = serviceB.Calc(o)
}
vs
program_OOP
{
var o = new obj(dep1,dep2, dep3, dep4)
var resultA = o.CalcA()
var resultB = o.CalcB()
}
You can see that if I have multiple unrelated operations to perform on the same data, OOP is going to get up with huge constructors with a million dependencies.
If I have a program which is only interested in resultA, I still need to create and inject the dependencies for resultB.
The OOP approach shines when you have multiple, related, state mutating, operations you want to conditionally perform on the same, persisted in memory object. ie a user interface
program_OOP
{
var o = new obj(dep1,dep2)
OnClickA += o.ChangeA()
OnClickB += o.ChangeB()
OnClickC += o.Print()
while(running) { drawUI(); }
}
Now you can pass o around the app mutating it as required without having to dig out the service you want from some a global var etc
The ADM approach shines when you have a multiple unrelated calculations to perform on collections of the objects. ie microservices/web apis
program_ADM_MS1
{
var serviceA = new service(dep1,dep2)
var serviceB = new service(dep3,dep4)
bind("/CalcA", o => return serviceA.Calc(o));
bind("/CalcB", o => return serviceB.Calc(o));
}
program_ADM_MS2
{
var serviceC = new service(dep5,dep6)
var serviceD = new service(dep7,dep8)
bind("/CalcC", o => return serviceC.Calc(o));
bind("/CalcD", o => return serviceD.Calc(o));
}
program_ADM_MS3
{
var serviceE = new service(dep9,dep0)
foreach(var o in repo.AllObjs())
{
serviceE.DoThing()
}
}