0

Let's say I have a Car class. Objects of this class will be stored in a collection, and every object should know about other elements in the collection, because for each car there's a value to be calculated based on the elements of the collection it belongs to.

That's a generalization of my problem, but I think it captures the idea pretty accurately. What is the right approach to this? Should I create a new CarLogic class, store cars in a collection and put all the logic for performing those calculations in the new class?

Or maybe it's better to just keep the reference to the collection which the Car object belongs to in Cars objects themselves + let the Car class should calculate those values?

  • What exactly is the collection you're talking about? When you mention a collection, all I can imagine is something like List<Car> in C#, std::vector<Car> in C++ or a simple array in a language like PHP or JavaScript. As you can see, a collection is usually a set of elements of the same type, but from your example it seems you mean something else with that expression. Could you also specify what exactly are you calculating? From that one can decide where the logic belongs. – Andy Mar 3 '16 at 20:41
  • @DavidPacker yes, what I mean could be a list in Java or C#. Let's say I'm summing up the engine power of the cars in the collection (of course I'm not doing this, it's an simplification) – user5539357 Mar 3 '16 at 21:06
  • 2
    In that case the Car should not really know where it's stored, in which collection. It's not its concern. You can create a simple class acting, either completely acting as a helper for processing a car collection, or acting as a service knowing how to manipulate with the collection based on some business rules. – Andy Mar 3 '16 at 21:29
  • If it is statistical in nature, your approach is correct and it would be called e.g. CarStatistics. If you only need to calculate exactly one thing, e.g. sum, then it would be a method called sum that takes in an array of Cars. – rwong Mar 3 '16 at 23:04
4

You have three concerns in this code:

  1. Aggregating/storing cars (Collection).
  2. Doing car things (Car).
  3. Calculate values for multiple cars (???).

You currently have the calculation not assigned to a class. Given that the concern is very different from the other two, it does not make sense to mix it into either existing class. Doing so violates SRP.

A clean design would assign this concern to a new class, a CarCalculator. Depending on the requirements of this calculation, it could be invoked in several ways. Two that come to mind:

  1. The code that populates the collection of cars could create the calculator and invoke it on the collection.

    Collection<Car> cars = new CollectionType();
    // Populate cars
    new CarCalculator().calculate(cars);
    return cars;
    
  2. The collection itself could be extended to invoke calculation logic.

    Collection<Car> cars = new MyCollectionType(new CarCalculator());
    // Populate cars: collection updates using its calculator
    return cars;
    

The benefit to either solution here is that cars do not need visibility into a collection (what if they are not in one?), and the collection can do what it does best: contain cars. The calculator does not need to manage cars (adding, removing, etc) nor does it store properties of cars. It just calculates stuff.

|improve this answer|||||
0

It depends on your actual case, that is the information you need to retrieve from a collection.

In some cases, an object could have a limited knowledge of its environment within the collection. For instance, doubly-linked lists may work this way. A Car will know both the previous and the next elements, and use this information to perform some action or manifest some behavior (for instance, a robot car current might follow current.Previous and send signals to current.Next so the next one would follow the current car. Or one may decide that the behavior of a doubly-linked list is the matter of the list itself (and the code processing the list), and it's not the Car's business to know the previous or the next car. In this case, the list will use a generic wrapper, such as DoublyLinkedListItem<T>, and it's this item which will contain both the Car object and the references to the previous and next items.

In other cases, you would rather put the logic outside the Car class, either in the collection itself (such as a Train is a collection of RailwayCars with its proper logic which has nothing to do within RailwayCar), or in a very different class.

Finally, there are cases where the logic belongs to the Car itself and depends on the collection, but the knowledge of the Car of its surroundings doesn't need to be extensive. Let's take an example where a car needs to know the total horsepower of the cars in the collection when starting the engine. In this case, instead of giving to the car the reference to the entire collection (and let every car loop through the whole collection and do the math, individually), you may simply compute the sum and give it to the car:

horsepower = cars.sum(c => c.horsepower);
sampleCar.startEngine(totalHorsepower: horsepower);
|improve this answer|||||
  • To be more specific: suppose every Car should know the total horsepower of the cars in the collections (list) it belongs to. Should I just store a List reference in every car and calculate it directly in the Car class? – user5539357 Mar 3 '16 at 21:20
  • @user5539357: I edited my answer to address specifically your example. See the last paragraph. – Arseni Mourzenko Mar 3 '16 at 21:47
  • 1
    I agree with the answer about how to get the carCollection-totalHorsepower to a given individual car. However I question why a car object needs this. I suspect there is some conceptual thing in your car domain that you are not clearly defining or have not told us. – radarbob Mar 4 '16 at 18:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.