Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design pattern for class with upwards of 100 properties

What advice/suggestions/guidance would you provide for designing a class that has upwards of 100 properties?

Background

  • The class describes an invoice. An invoice can have upwards of 100 attributes describing it, i.e. date, amount, code, etc...
  • The system we are submitting the invoice to uses each of the 100 attributes and is submitted as a single entity (as opposed to various parts being submitted at different times).
  • The attributes describing the invoice are required as part of the business process. The business process can not be changed.

Suggestions?

  • What have others done when faced with designing a class that has 100 attributes? i.e., create the class with each of the 100 properties?
  • Somehow break it up (if so, how)?
  • Or is this a fairly normal occurrence in your experience?

EDIT After reading through some great responses and thinking about this further, I don't think there really is any single answer for this question. However, since we ended up modeling our design along the lines of LBrushkin's Answer I have given him credit. Albeit not the most popular answer, LBrushkin's answer helped push us into defining several interfaces which we aggregate and reuse throughout the application as well as a nudged us into investigating some patterns that may be helpful down the road.

like image 856
Metro Smurf Avatar asked Oct 27 '09 19:10

Metro Smurf


4 Answers

You could try to 'normalize' it like you would a database table. Maybe put all the address related properties in an Address class for example - then have a BillingAddress and MailingAddress property of type Address in your Invoice class. These classes could be reused later on also.

like image 52
Philip Wallace Avatar answered Nov 15 '22 04:11

Philip Wallace


The bad design is obviously in the system you are submitting to - no invoice has 100+ properties that cannot be grouped into a substructure. For example an invoice will have a customer and a customer will have an id and an address. The address in turn will have a street, a postal code, and what else. But all this properties should not belong directly to the invoice - an invoice has no customer id or postal code.

If you have to build an invoice class with all these properties directly attached to the invoice, I suggest to make a clean design with multiple classes for a customer, an address, and all the other required stuff and then just wrap this well designed object graph with a fat invoice class having no storage and logic itself just passing all operations to the object graph behind.

like image 22
Daniel Brückner Avatar answered Nov 15 '22 05:11

Daniel Brückner


I would imagine that some of these properties are probably related to each other. I would imagine that there are probably groups of properties that define independent facets of an Invoice that make sense as a group.

You may want to consider creating individual interfaces that model the different facets of an invoice. This may help define the methods and properties that operate on these facets in a more coherent, and easy to understand manner.

You can also choose to combine properties that having a particular meaning (addresses, locations, ranges, etc) into objects that you aggregate, rather than as individual properties of a single large class.

Keep in mind, that the abstraction you choose to model a problem and the abstraction you need in order to communicate with some other system (or business process) don't have to be the same. In fact, it's often productive to apply the bridge pattern to allow the separate abstractions to evolve independently.

like image 12
LBushkin Avatar answered Nov 15 '22 03:11

LBushkin


Hmmm... Are all of those really relevant specifically, and only to the invoice? Typically what I've seen is something like:

class Customer:
.ID
.Name

class Address
.ID 
.Street1
.Street2
.City
.State
.Zip

class CustomerAddress
.CustomerID
.AddressID
.AddressDescription ("ship","bill",etc)

class Order
.ID
.CustomerID
.DatePlaced
.DateShipped
.SubTotal

class OrderDetails
.OrderID
.ItemID
.ItemName
.ItemDescription
.Quantity
.UnitPrice

And tying it all together:

class Invoice
.OrderID
.CustomerID
.DateInvoiced

When printing the invoice, join all of these records together.

If you really must have a single class with 100+ properties, it may be better to use a dictionary

Dictionary<string,object> d = new Dictionary<string,object>();
d.Add("CustomerName","Bob");
d.Add("ShipAddress","1600 Pennsylvania Ave, Suite 0, Washington, DC 00001");
d.Add("ShipDate",DateTime.Now);
....

The idea here is to divide your into logical units. In the above example, each class corresponds to a table in a database. You could load each of these into a dedicated class in your data access layer, or select with a join from the tables where they are stored when generating your report (invoice).

like image 6
3Dave Avatar answered Nov 15 '22 03:11

3Dave