dennis-fedco Posted July 10, 2014 Share Posted July 10, 2014 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? Quote Link to comment Share on other sites More sharing options...
requinix Posted July 10, 2014 Share Posted July 10, 2014 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. 1 Quote Link to comment Share on other sites More sharing options...
dennis-fedco Posted July 10, 2014 Author Share Posted July 10, 2014 (edited) 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 July 10, 2014 by dennis-fedco Quote Link to comment Share on other sites More sharing options...
dennis-fedco Posted July 10, 2014 Author Share Posted July 10, 2014 (edited) I ended up doing this: $dimensions = $this->getDimensions($options); $weight = $this->getWeight($options); each method calls its own factory to get object and then calls object's method to get weight/dims. Edited July 10, 2014 by dennis-fedco Quote Link to comment Share on other sites More sharing options...
ignace Posted July 12, 2014 Share Posted July 12, 2014 Why do you require a factory to get basic properties from a Crate object? Shouldn't it be: $crate->getDimensions(); $crate->getWeight();Whatever that $options variable hold should be modelled into your Special Case Crate object. Quote Link to comment Share on other sites More sharing options...
dennis-fedco Posted July 14, 2014 Author Share Posted July 14, 2014 (edited) 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 July 14, 2014 by dennis-fedco Quote Link to comment Share on other sites More sharing options...
Solution KevinM1 Posted July 14, 2014 Solution Share Posted July 14, 2014 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. 1 Quote Link to comment Share on other sites More sharing options...
dennis-fedco Posted July 14, 2014 Author Share Posted July 14, 2014 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 . . . Quote Link to comment Share on other sites More sharing options...
ignace Posted July 15, 2014 Share Posted July 15, 2014 When assigning responsibilities you should keep in mind that Crate is the Information Expert: http://en.wikipedia.org/wiki/GRASP_(object-oriented_design)#Information_Expert SRP is about the big picture, class cohesion, not about trimming all classes until they only have 1 method. 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.