Home Technology Improving the Music Inventory Example from Head First Object Oriented Analysis and Design

Improving the Music Inventory Example from Head First Object Oriented Analysis and Design

by Al

I’ve been refreshing my knowledge of software design by working through the book, ‘Head First Object Oriented Analysis and Design.’

One of the examples that they use to show how designs can evolve and be improved upon over time is an application that is used to track musical instruments inventory. The initial design of the app is poor in that it lacks maintainability and requires modification of existing classes (one of the no-no’s of SOLID design principles) and the addition of many new classes any time you want to add a new instrument type to the application. In chapter 5 of the book, they improve the design considerably by replacing unique classes for each instrument with a single class, InstrumentSpec that maintains a list of properties for the instrument that it represents. Not only does this eliminate the need for the creation of a new instrument class, it also allows you to dynamically add new properties to each class instead of having them hardwired into the class.

While I agree with them about the software being greatly improved, I still feel there’s one glaring problem with it. When a new property is added to the InstrumentSpec class it uses a key/value pair to store the property. For the key, they’ve chosen to use the string type. While this gives you a lot of flexibility, I feel it’s pretty much a disaster waiting to happen. Not only does the user of InstrumentSpec has to be relied upon to make sure the string is a valid value and is spelled correctly, if a mistake is made it won’t be found at compile time but instead will manifest itself at runtime. The last thing you want happening is your software to fail in the field instead of failing when you’re designing it. Granted a lot of this can be avoided by the use of appropriate test cases but that still takes a leap of faith that the error will be caught.

A better way to handle this is to replace the string key with an enumeration key. This prevents the user from ever using an invalid key and also prevents the code from compiling if an incorrect key is used. The only downside to this approach is that you have to modify the PropertyKey enumeration any time you add a new property to the software. To me this seems a minor tradeoff that goes a long way towards creating more robust software.

The following example shows the use of property keys instead of strings.

InstrumentSpec.cs

using System;
using System.Collections.Generic;

namespace CH3_Guitar_Application
{
    internal class InstrumentSpec
    {
        private Dictionary<PropertyKeys, object> _properties;

        public InstrumentSpec(Dictionary<PropertyKeys, object> properties)
        {
            if (properties == null)
                _properties = new Dictionary<PropertyKeys, object>();
            else
                _properties = new Dictionary<PropertyKeys, object>(properties);
        }

        public object GetProperty(PropertyKeys propertyName)
        {
            return _properties[propertyName];
        }

        public Dictionary<PropertyKeys, object> GetProperties()
        {
            return _properties;
        }

        public Boolean Matches(InstrumentSpec otherSpec)
        {
            foreach (var property in otherSpec.GetProperties())
            {
                if (!_properties.TryGetValue(property.Key, out var value))
                    return false;

                if (property.Value != value)
                    return false;
            }

            return true;
        }
    }
}

PropertyKeys.cs

namespace CH3_Guitar_Application
{
    internal enum PropertyKeys
    {
        INSTRUMENT_TYPE,
        BUILDER,
        MODEL,
        INSTRUMENT_STYLE,
        NUM_STRINGS,
        TOP_WOOD,
        BACK_WOOD
    }
}

A second problem that I ran into was because of my choice of rewriting the examples in C# instead of doing them in Java like the book does.

The original application prints out a human readable string based on the value of an enumeration. This string is different than the actual name of the enumeration and is not a problem in Java. Unfortunately, in C# the enum type is limited and if you attempt to use the ToString() method to print out the enum, it will display the actual enum text instead of something that is tailored for readability.

To fix this problem, I replaced the enum type with the Enumeration class written by Jimmy Bogard. https://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/ Not only does this class allow you to associate a human readable string with an enumeration, it also allows you to add methods to the enumeration if you need to perform other operations when using the enum. Most of the time you won’t need all this extra functionality and regular enums will do just fine but if you ever do, it’s nice to know this class is available.

Here’s an example of using the Enumeration class. Just subclass the Enumeration class, add your enumeration values with a human readable string and you’re good to go.

InstrumentType.cs

namespace CH3_Guitar_Application
{
    public class InstrumentType : Enumeration
    {
        public static readonly InstrumentType GUITAR = new InstrumentType(0, "Guitar");
        public static readonly InstrumentType BANJO = new InstrumentType(1, "Banjo");
        public static readonly InstrumentType DOBRO = new InstrumentType(2, "Dobro");
        public static readonly InstrumentType FIDDLE = new InstrumentType(3, "Fiddle");
        public static readonly InstrumentType BASS = new InstrumentType(4, "Bass");
        public static readonly InstrumentType MANDOLIN = new InstrumentType(5, "Mandolin");
        public static readonly InstrumentType ANY = new InstrumentType(6, "Unspecified");

        private InstrumentType()
        {
        }

        private InstrumentType(int value, string displayName) : base(value, displayName)
        {
        }
    }
}

You may also like

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.