Jump to content

SRP with a "crate" object


dennis-fedco
Go to solution Solved by KevinM1,

Recommended Posts

Suppose I am coding up a crating calculator.  A crate is a box with dimensions, weight, built of certain material, and having certain contents.

 

The crating calculator I am writing is one that computes dimensions of the box, once given dimensions of variou contents put into it.

Right now I have a factory that figures out which contents object to create, in order to figure out contents dimensions.

 

Something like

class CrateDimensionFactory 
{
    function getDimensionAwareClass(array $options)
    {
        return $dimensionAwareObject;
    }
}

//later in some code:
$dimensionAwareObject->getDimensions();

Now, I want to also put in the weight of crate which is the sum of contents of crate plus the weight of the crate.

Question ... do I stick the weight computations into the same factory?  i.e.

class CrateFactory 
{
    function getDimensionAwareClass(array $options)
    {
        return $dimensionAwareObject;
    }

    function getWeightAwareClass(array $options)
    {
        return $weightAwareObject;
    }
}

//later in some code:
$dimensionAwareObject= (new CrateFactory())->getDimensionAwareClass($options);
$dimensionAwareObject->getDimensions();

$weightAwareObject= (new CrateFactory())->getWeightAwareClass($options);
$weightAwareObject->getWeight();

I can even stick the weight into the same returned object, where I create a single object from Factory, and then just call

$crateAwareObject= (new CrateFactory())->getCrateAwareClass($options);
$crateAwareObject->getDimensions();
$crateAwareObject->getWeight();

There are many ways to do it .. I guess.  But the spirit of my question is -- should I, do I put dimensions and weights together or separately, and how exactly do I separate them or how exactly do I put them together, with regards to how SRP is concerned?

Link to comment
Share on other sites

I think the idea of a "crate dimension factory" is confusing me as to how this all works... Do you have a concrete example of the system at work?

 

My off-the-cuff preference would be towards a factory factory: dimension things have a factory, weight things have a factory, and there's an overarching factory producing the dimension and weight factories. Some of that implementation could be hidden with a(nother) class that looks like a regular factory (one such as you proposed) but that secretly uses the various factories behind the scenes.

  • Like 1
Link to comment
Share on other sites

hah.. I have at least 17 classes that make this thing work ... ......

 

but yes basically I have ..

//So I have CrateDimensionFactory factory. it returns proper object
$cratingCalculator = (new CrateDimensionFactory())->getDimensionAwareClass($options); //options contain product specs
//from object I get dimensions
$cratingCalculator->getCrateDimensions(); // returns dimensions

Somewhere else I have a combine() method, where I run various possible combinations of products, where user can look them over and decide which one the like best.  In the end I may end up with line items like

* product 1 (only)  //my method returns dimensions for this one object

* product 2 + product 1 //my method returns dimensions for both

 

So the combine() method puts things together and will be a good place to put the code for summing the weights as well.

 

I can thus either create a new class that figures out the weights, or put the weights into the "dimension" classes (since those classes can be easily used and already exist in combine() method).  I am leaning towards separate classes now as ... better be safe than sorry and "weights" and "dimensions" are different, and even if I separate them needlessly, I think it won't be too bad.

Edited by dennis-fedco
Link to comment
Share on other sites

I am still having a problem with this. . .

 

 

wouldn't this:

$crate->getDimensions();
$crate->getWeight();

cause multiple responsibilities? 

 

In this case when I create a crate, I will need to pass initial variables for dimensions, and for weight.  Initial (input) variables for dimensions are different than those for weight.  They could be separated into different classes, such as
 

$crateDimensions->getDimensions();
$crateWeight->getWeight();

... but then my main abstract Crate class does have (and perhaps should) provide both dimensions and weights.

 

I am conflicted because I have this one class that goes like this (that's the one that uses different variables for weight/dimensions), where different variable groups are {$id, $sections}, and {$size}

class CrateTypeA extends Crate
{
    function __construct($options)
    {
        // Declarations
        $id = $options['id'];
        $size = $options['size'];
        $sections= $options['sections'];
            
        // Dimensions
        $this->length = (new TypeAData())->length($size);
        $this->width = (new TypeAData())->width($size);
        $this->height  = (new TypeAData())->height($size);
         
        
        // Weight
        $this->weight = (new TypeAWeightData())->getWeight($id, $sections);
    }
}
Edited by dennis-fedco
Link to comment
Share on other sites

  • Solution

Why would a crate knowing its own physical properties create two responsibilities? I mean, yeah, you can get pedantic and separate the properties in terms of being a measurement of length (dimensions) and mass (weight), but that's way overthinking it.

 

Don't get hung up on following SOLID to the nth degree. SOLID principles naturally follow from these two adages:

 

1. Code to an abstraction, not an implementation

2. Each class should focus on one thing

 

A crate has physical properties. Weight is one of them. Unless including its weight in a class dramatically changes how that class behaves (i.e., if handling the weight is special/different from everything else), then don't sweat it.

  • Like 1
Link to comment
Share on other sites

I did find one downside to this aside from SRP:

 

I compute dimensions first, then weight.  If code computing dimensions happens to hit a snag and throw an exception, it pulls out of the class, BEFORE computing weight.  So weight is not being displayed when dimensions are "bad", despite the fact that weight can still be computed and shown in many of the circumstances.

 

Aka code doing the weight computations is dependent on the code doing dimensions.


I suppose instead of doing computations of dimensions and weight in constructor, I can just assign parameters in constructor, and move the weight/dimensions into separate functions and call those separately . . .

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.