I have Product classes for Products A through Z. And each Product class has its own set of product-specific subclasses, which I'd say are tightly coupled to them, like so:
//specific product class inherits from generic product
class ProductA extends Product
{
function __construct()
{
parent::__construct();
//product-specific subclasses that are tightly coupled to the product
//note that they are not DI-ed, although they *could be*
$this->weight = new WeightA();
$this->spec = new SpecA();
}
}
class Product
{
public $weight;
public $spec;
function __construct()
{
//these are generic versions in case someone calls a generic product class
$this->weight = new Weight();
$this->spec = new Spec();
}
}
//example instantiation
$p = new ProductA();
$p->weight->a_specific = 4;
Question:
I spent a bit of time reflecting on whether I wanted to pass my Weight
and Spec
subclasses using Dependency-Injection techniques, like so (adjusting my classes respectively):
$p = new ProductA(new WeightA(), new SpecA());
But so far I have found no good reason to do so. In fact, doing so may increase the chance of error where I can by accident do something like this:
$p = new ProductA(new WeightB(), new SpecC()); //note the disparate classes
Question:
- Are there any good reason to DI tightly-coupled subclasses into generic class containers anyway?
- is there a common name for this issue (pattern) that I am dealing with?
- are there other (better) patterns available to use in my instance?
Background:
I am refactoring a large ball-of-mud application and it is getting some shape, but one of the patterns I have identified is that there are product-specific classes that contain a lot of product-specific sub-classes, such as in the above example.
Possible Middle-Ground:
Note: alternatively if I really want to DI, I can use DI inside product-specific subclasses, injecting subclasses into the parent container (opposed to injecting it from the outside into the product-specific classes themselves like I have done above), like so:
class ProductA extends Product
{
function __construct()
{
parent::__construct(new WeightA(), new SpecA());
}
}
class Product
{
function __construct($weight, $spec)
{
$this->weight = $weight;
$this->spec = $spec;
}
}
I wonder if that will be a better option overall. One problem with it is that ProductA()
has no parameters but Product($weight, $spec)
will have two parameters, which is an inconsistency.