views:

167

answers:

3

I'm a rusty programmer attempting to become learned in the field again. I've discovered, fitfully, that my self-taught and formal education both induced some bad habits. As such, I'm trying to get my mind around good design patterns, and -- by extension -- when they're wrong. The language is Java, and here's my issue:

I'm attempting to write software to assist in beer brewing. In brewing, sometimes you must substitute a particular variety of hop for what's called for in the recipe. For example, you might have a recipe that calls for 'Amarillo' hops, but all you can get is 'Cascade', which has a similar enough aroma for substitution; hops have an Alpha Acid amount (per a given mass), and the ratio between two hops is part of the substitution formula. I'm attempting to model this (properly) in my program.

My initial go is to have two objects. One a HopVariety, which has general descriptive information about a variety of hop, and one a HopIngredient, which is a particular instantiation of a HopVariety and also includes the amount used in a given recipe. HopIngredient should have knowledge of its variety, and HopVariety should have knowledge of what can be used as a substitute for it (not all substitutions are symmetric). This seems like good OOP.

The problem is this: I'm trying to follow good practice and make my value objects immutable. (In my head, I'm classifying HopVariety and HopIngredient as value objects, not 'actors'.) However, I need the user to be able to update a given HopVariety with new viable substitutions. If I follow immutability, these changes will not propagate to individual ingredients. If choose mutability, I'm Behaving Badly by potentially introducing side-effects by sharing a mutable value object.

So, option B: introduce a VarietyCollection of sorts, and loosely couple the ingredients and the varieties by way of a name or unique identifier. And then a VarietySubstitutionManager, so that varieties don't hold references to other varieties, only to their ids. This goes against what I want to do, because holding a reference to the variety object makes intuitive sense, and now I'm introducing what feels like excessive levels of abstraction, and also separating functions from the data.

So, how do I properly share state amongst what amounts to specific instances? What's the proper, or at least, sanest way to solve the problem?

A: 

I think your choices are either to

  • have the 'update variety' function walk the existing object graph and create a new one with all of the ingredients updated, or
  • keep using mutability

With the information at hand, it isn't clear to me which is better for your situation.

Brian
A: 

Are you sure HopVariety should be a value object? It sounds to me like an entity - "Amarillo" hop variety is one and only one, so it should be a uniquely identifiable object. Just like "Tony Wooster" is only one (well not exactly, but you get the point ;) )

I recommend reading about Domain Driven Design and the differences between entities and value objects.

BTW: DDD book has a lot of examples of situations like yours and how to handle them.

Igor Brejc
A: 

How badly do you want to avoid mutation of objects with multiple references?

If you want the recipe collection to reflect the user updates to the variety set, and you want to avoid mutable fields in your objects, then you'll be forcing yourself into using functional object update to handle user input.

At the end of that road lies the I/O monad. How far do you want to go in that direction?

With a functional language that allows mutation side-effects, e.g. S/ML etc., you might opt to keep your variety and ingredient objects pure, and to store functions that return the current variety object from the latest variety collection stored in a single mutable reference cell. This might seem like a reasonable way to split the difference.

james woodyatt