简体   繁体   中英

Class design for domain object and container of these objects

we were having a discussion today at work about a recurring situation in our codebase: Say we have a particular domain object in our software (eg Customer). Additionally we have a group of customers relevant for a specific use case in our system. We have business logic that works on a specific customer (eg getRevenue()) and other parts that work on the whole group of customers (eg getAverageRevenue(), getNumberOfActiveCustomers(),...). The group functionality also includes methods that changes certain Customers in the group, or that searches for certain sub groups in the group,etc.. (eg getCustomersWithoutOrdersSince()).

How would you go about such a situation:

  1. Make a Customer class and a CustomerGroup class: The CustomerGroup class has its customers in a private member std::vector (or in Java in a List). Group related functionality is implemented as member functions of CustomerGroup.
  2. Make just a Customer class, Leave the std::vector (or List) of customers with the caller: Add single customer functionality in member functions of Customer. CustomerGroup related functionality is realised as static methods of Customer (eg: static int getAverageRevenue(vector &custVector) or in Java static int getAverageRevenue(List))
  3. Variation of Nr. 2 (C++ only): Make just a Customer class, Leave the vector of customers with the caller implement CustomerGroup functionality as non-member functions in namespace Customer
  4. ...

How would you implement such a scenario or what are the advantages/disadvantages in your opinion.

In item 23 of "Effective C++" ("Prefer non-member non-friend functions to members functions") Scott Meyers advocate to move stuff out of classes in non-member functions. This would resemble design number 3 in my opinion. I find this advice odd and counterintuitive however. @jrahhali commented that this might be to adhere to the single responsibility principle. Any thoughts/posts/URL's on that are welcome (unfortunately I didn't find any good discussion on item 23).

Thanks in advance for your input.

  1. I like this the best. It is intuitive to have methods that act on a customer in a Customer class, and its intuitive to have methods that act upon a group on Customers in a CustomerGroup class. You also have your CustomerGroup encapsulating its representation of a group of customers, and it provides a nice location for all future group-related operations to live. It's not static, so you have the option of thread safety, if that's important. CustomerGroup also provides more meaning than just a vector or List.

  2. This is also not bad. You are still providing a place to group related behaviour, but this time in static methods on the Customer class. I personally think static methods are more procedural like than OO like, and for that reason, still prefer #1. But, at the end of the day, #1 and #2 are very similar in that they both achieve a DRY approach.

  3. This is even more procedural than #2, but still acheives the same result.

I guess the answer depends on how OO and/or procedural you want to code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM