开发者

Which design pattern to use?

开发者 https://www.devze.com 2023-02-24 06:11 出处:网络
I was asked in a recent interview: A Sandwich should have exactly two slices of bread (one on each end), and any positive number of Cheeses in between.

I was asked in a recent interview:

A Sandwich should have exactly two slices of bread (one on each end), and any positive number of Cheeses in between.

Sandwich s = new Sandwich();
s.add(new BreadSlice());
s.add(new CheddarCheese());
s.add(new SwissCheese());
s.add(new BreadSlice());
System.println("My sandwich: "+ s.toString());

What design pattern could you use to ensure that every Sandwic开发者_运维百科h instantiated is a valid sandwich?


You could use a Builder pattern: Used for very complicated multi-step object construction, where the number of constructor or method arguments would be ridiculously high.

SandwichBuilder sb = new SandwichBuilder();
sb.addFirstBread(new BreadSlice());
sb.addCheese(new Cheese());
...
sb.addLastBread(new BreadSlice());
Sandwich s = sb.getSandwich();

incomplete SandwichBuilders could throw some kind of IncompleteSandwichException if not completed correctly when .getSandwich() is called.

Note: with properly named construction methods, you don't need to do anything in a specific order.

Or you could use a FactoryMethod pattern: When the number of steps would fit into a single method call with a reasonable number of arguments, and the object should be guaranteed to be a complete state.

BreadSlice bs1 = new BreadSlice();
BreadSlice bs2 = new BreadSlice();
List<Cheese> cheeses = new ArrayList<Cheese>();
...
Sandwich s = SandwichBuilder.buildSandwich(bs1, cheeses, bs2);

Or use the Constructor: which is a specialized case of FactoryMethod pattern

Sandwich s = new Sandwich(bs1, cheeses, bs2);

overloaded constructor to allow for cheese addition:

Sandwich s = new Sandwich(bs1, bs2);
s.addCheese(new CheeseSlice());
...

There are lots of ways to do this depending on how strict you want the construction to be. For example, you can make the Sandwich implementation an inner class of the Factory/Builder object and make its constructor private so it can't be instantiated in-correctly.


I think the Builder pattern could be a good choice here.


I have implemented the solution using

Template pattern.

Though the solution is in C# it can easily be modified to run in Java environment.


using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            DeliverSandwitch(new MinimumCheese());
            DeliverSandwitch(new MixCheese());
            DeliverSandwitch(new DoubleSwissCheese());
            Console.ReadLine();
        }

        private static void DeliverSandwitch(BaseSandwitch customSandwitch)
        {
            Console.WriteLine(customSandwitch.Name);
            Console.WriteLine("-----------------------------------");
            foreach (string layer in customSandwitch.Layers)
                Console.WriteLine(layer);

            Console.WriteLine();
            Console.WriteLine();
        }

        public abstract class BaseSandwitch
        {
            List<string> layers = new List<string>();
            protected virtual CheeseType DefaultCheese { get { return CheeseType.PlainCheese; } }
            public abstract string Name { get; }
            public BaseSandwitch()
            {
                SandwitchTemplate();
            }

            private void SandwitchTemplate()
            {
                AddBaseBread();
                AddCheese(DefaultCheese);
                AddAdditionalCheese();
                AddTopBread();
            }

            private void AddTopBread()
            {
                layers.Add("Top bread");
            }

            public abstract void AddAdditionalCheese();

            private void AddBaseBread()
            {
                layers.Add("Base bread");
            }

            protected void AddCheese(CheeseType cheeseType)
            {
                layers.Add(cheeseType.ToString());
            }

            public IEnumerable<string> Layers { get { return layers; } }
        }

        class MinimumCheese : BaseSandwitch
        {
            public override string Name { get { return "Minimum cheese Sandwitch"; }}
            public override void AddAdditionalCheese()
            {
                // I come with no additional cheese
            }

            // I do not like PlainCheese. Replacing with CheddarCheese
            protected override CheeseType DefaultCheese
            {
                get { return CheeseType.CheddarCheese; }
            }
        }

        /// <summary>
        /// I am ok with default cheese and would like to have other cheese as well
        /// </summary>
        class MixCheese : BaseSandwitch
        {
            public override string Name { get { return "Mix cheese Sandwitch"; } }
            public override void AddAdditionalCheese()
            {
                AddCheese(CheeseType.CheddarCheese);
                AddCheese(CheeseType.SwissCheese);
            }
        }

        class DoubleSwissCheese : BaseSandwitch
        {
            public override string Name { get { return "Double Swiss Cheese Sandwitch"; } }
            public override void AddAdditionalCheese()
            {
                // Adding another layer of swiss cheese
                AddCheese(CheeseType.SwissCheese);
            }

            // I like swiss cheese by default instead of PlainCheese
            protected override CheeseType DefaultCheese
            {
                get { return CheeseType.SwissCheese; }
            }
        }

        public enum CheeseType { PlainCheese, SwissCheese, CheddarCheese };
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消