Teaser Image

qnoid

Markos Charatzas - London, UK




/**
     * A new and improved SurvivalKit supporting any items you like!
     */
    public class SurvivalKit
    {
        /**
         * Helps you build a survival kit and customize it the way you like!
         */
        public static final class SurvivalKitBuilder
        {
            public enum Size
            {
                TWO_XL, XL, LARGE, MEDIUM, SMALL;
            }

            private static final int COST = 29;        
            private final Collection <SurvivalKitItem> items;

            /**
             */
            public SurvivalKitBuilder()
            {
                this.items = new ArrayList<SurvivalKitItem>();
            }
            
            /**
             * @param items the items to add
             * @return the builder for chaining
             */
            public SurvivalKitBuilder add(SurvivalKitItem... items)
            {
                this.add( Arrays.asList(items) );
            return this;
            }
            
            /**
             * @param items the items to add
             * @return the builder for chaining
             */
            public SurvivalKitBuilder add(List<? extends SurvivalKitItem> items) {
                this.items.addAll(items);
            return this;
            }

            /**
             * @return a new SurvivalKit containing all the items
             */
            public SurvivalKit build() {
            return new SurvivalKit(this.items, COST);
            }
        }
        
        /**
         * Having a collection of items will eliminate the need for null
         * plus we can use the {@link SurvivalKit} to include even more
         * items in the future without changing a single line of code!
         * 
         * Future items can be added to the survival kit!
         */
        private final Collection <SurvivalKitItem> items;
        private final int cost;

        /**
         * @param items what will your kit have
         * @param cost what it costs
         */
        private SurvivalKit(Collection<SurvivalKitItem> items, int cost)
        {
            this.items = items;
            this.cost = cost;
        }

        /**
         * @return the items
         */
        public Collection<SurvivalKitItem> getItems() {
        return items;
        }

        /**
         * @return the cost
         */
        public int getCost() {
        return cost;
        }    
    }

    /**
     * The "marker" interface
     */
    public interface SurvivalKitItem
    {

    }

    /**
     * Mark your items!
     */
    public class TShirt implements SurvivalKitItem{}

    public class Wristband implements SurvivalKitItem{}

    public class Sticker implements SurvivalKitItem{}

    public class Mug implements SurvivalKitItem{}

The survival kit has been great so far. We identified its class and also defined a builder to help us create new kits the fun way.

That was until @kyle decided that there can be one without a TShirt. So how would you go on about it?

There is the option to create a new SurvivalKit class without the TShirt. But in doing so you have to also think of all the relationships that it has. Like SurvivalKitOrder or the ForrstController. Will you create extra classes for those relationships as well? Your code isn't that DRY anymore.

You could use a base survival kit which includes everything but a TShirt and have your SurvivalKit extend that, adding a TShirt. You are abusing inheritance now.

You can simply use your existing SurvivalKit class and just use a null value anytime you don't want a TShirt. By doing so though you will end up having to check every time you access the TShirt if it's null or not. What's worse is if you have to make a decision based on that when you really shouldn't.

How will you handle a future SurvivalKit that may have less or even more items (Hint) that go with it? You start to notice that this doesn't scale well.

The real question you have to ask yourself is, "How much different are those SurvivalKit(s)?". Talking about different survival kit's is more directly related to different implementations rather on the properties that make it up.

If you rethink of what defines a SurvivalKit you will come to realise that it's merely the items that is has. So you could say that the TShirt, the Mug, the Wristband and the Sticker are all SurvivalKitItem(s).

From the description of the kit we can't really tell anything about a SurvivalKitItem yet we can simply define a marker interface that designates all the items that can be added to the kit.

All you have to do is have each implement the SurvivalKitItem interface.

You can see that the SurvivalKit#build no longer returns a new kit. So where do we specify the custom kit that we want?