FizzBuzzWhizz是算法题吗?我从设计的角度去解决的。

今天在网上看到FizzBuzzWhizz这个代码挑战啊。觉得很有意思。开始没有看其他人的文章。写完之后,好像大家都是从算法的角度去解决问题啊。我却是一开始从设计的角度去解决问题。不知道他们出这道题到底是要考验算法呢?还是面向对象的设计呢?但是我看要求里写了要体现超赞的面向对象设计啊。而且我看了他们公司,也是一个以设计专长的公司。是要考虑算法的问题吗?

首先,我看到这道题。现在是有三种特殊数字。分别是Fizz、Buzz、和WHizz。这就是对应三个类吧。至于当某一个数字即是第一个数的倍数又是第二个数的倍数时,就要调用Fizz类和Buzz类来处理。所以我想。某一个数字要走的流程应该是先从Fizz类处理事件,再到Buzz类处理事件,最后到Whizz类处理。是穿透的。这样的流程,类似于行为型的设计模式吧。有哪些,脑子里应该有个大概的轮廓了。可能有责任链模式、装饰者模式、状态模式等。当然这些东西不重要。重要的是思想,不能死套用模式。本来想用类似于事件机制来实现的。可是发现,这样一来,Fizz、Buzz这些类就跟事件类耦合了。这样不好。并且,我想他们要考察的不是完成他们明文写的需求上的东西吧。更要考虑的是以后那些可以预见的需求变化。比如说,我可能这个时候不要输出字符了,我要进行别的操作。又或者是我要增加一个特殊数字。变成4个。这样一来,那么写算法的同学们是不是会非常的苦恼呢?至于,我用的什么模式,我只想说,我不清楚。我做设计的时候,从来不从模式出发,我是从灵活度和扩展性出发。如果现有代码不能满足可预见的变化。那就改成可以适应变化的。所以,代码的设计,其实并不是一种设计模式就能搞定的。是设计思想的融合。

我的思路是,将某个数字被某个特殊数字捕捉到要处理的情况。原先是直接输出字符。我想以后可能会不光是输出字符。所以,我将这部分的行为放到了外面。通过委托的方式调用。而且,考虑到这个题目本身就是输出字符,如果,我要在外部定义委托。那么对外的接口,就会变得复杂。我希望的是,对外的接口变得简单。就类似于外观模式。

在考虑到,以后如果要增加一个特殊数字,我希望能自由的组合这些流程。所以,就有了类似于装饰着模式或者责任链模式的设计。

/// <summary>
    /// 第二个特殊数字类
    /// </summary>
    public class Buzz : IFizzBuzzWhizz
    {
        /// <summary>
        /// 创建第二个特殊数字处理类实例
        /// </summary>
        /// <param name="specialNumber">特殊数字</param>
        /// <param name="nextFlow">下一个流程,这里指第三个特殊字处理类</param>
        /// <param name="multipleAction">当某个数字被这个类Handle的时候,要执行的事件(这里默认是如果某个数字是这个特殊数字的倍数,就在控制台输出一段字符)</param>
        public Buzz(int specialNumber, IFizzBuzzWhizz nextFlow, Action<int, bool> multipleAction)
        {
            this.SpecialNumber = specialNumber;
            this.NextFlow = nextFlow;
            this.MultipleAction = multipleAction;
        }

        public Buzz(int specialNumber, Action<int, bool> multipleAction)
            : this(specialNumber, new Whizz(7), multipleAction)
        {
        }

        public Buzz(int specialNumber)
            : this(specialNumber, new Whizz(7), (number, isHandle) => Console.Write("{0}Buzz", isHandle ? string.Empty : "\r\n"))
        {
        }

        /// <summary>
        /// 当某个数字是这个特殊数字的倍数的时候,要执行的事件
        /// </summary>
        public Action<int, bool> MultipleAction { get; set; }

        /// <summary>
        /// 特殊数字
        /// </summary>
        public int SpecialNumber { get; set; }

        /// <summary>
        /// 下一个流程,这里指第三个特殊数字处理类
        /// </summary>
        public IFizzBuzzWhizz NextFlow { get; set; }

        /// <summary>
        /// 处理方法
        /// </summary>
        /// <param name="number">数字</param>
        /// <param name="isHandle">是否被处理过</param>
        public void Process(int number, bool isHandle)
        {
            //如果当前的数字是这个特殊数字的倍数,就执行事件。并且标记isHandle为True,传递到下一个流程。
            if (number % this.SpecialNumber == 0)
            {
                if (this.MultipleAction != null)
                    this.MultipleAction(number, isHandle);
                isHandle = true;
            }
            if (this.NextFlow != null)
                this.NextFlow.Process(number, isHandle);
        }
    }
View Code
/// <summary>
    /// 特殊数字第一个类
    /// </summary>
    public class Fizz : IFizzBuzzWhizz
    {
        /// <summary>
        /// 构造一个第一个特殊数字的处理类实例
        /// </summary>
        /// <param name="specialNumber">特殊数字</param>
        /// <param name="nextFlow">下一个流程,这里值第二个特殊数字处理类实例</param>
        /// <param name="containsSpecialNumberAction">当某个数字包含当前的特殊数字时,要执行的事件,这里默认是输出一段字符</param>
        /// <param name="multipleAction">当某个数字是当前特殊数字的倍数时,要执行的事件</param>
        public Fizz(int specialNumber, IFizzBuzzWhizz nextFlow, Action<int> containsSpecialNumberAction, Action<int, bool> multipleAction)
        {
            this.SpecialNumber = specialNumber;
            this.NextFlow = nextFlow;
            this.ContainsSpecialNumberAction = containsSpecialNumberAction;
            this.MultipleAction = multipleAction;
        }

        public Fizz(int specialNumber, Action<int> containsSpecialNumberAction, Action<int, bool> multipleAction)
            : this(specialNumber, new Buzz(5), containsSpecialNumberAction, multipleAction)
        {
        }

        public Fizz(int specialNumber)
            : this(specialNumber, new Buzz(5), delegate { Console.Write("\r\nFizz"); }, (number, isHandle) => Console.Write("\r\nFizz"))
        {
        }

        /// <summary>
        /// 当某个数字包含当前的特殊数字时,要执行的事件
        /// </summary>
        public Action<int> ContainsSpecialNumberAction { get; set; }

        /// <summary>
        /// 当某个数字是当前特殊数字的倍数时,要执行的事件
        /// </summary>
        public Action<int, bool> MultipleAction { get; set; }

        /// <summary>
        /// 特殊数字
        /// </summary>
        public int SpecialNumber { get; set; }

        /// <summary>
        /// 下一个特殊数字处理类,这个默认值第二个特殊数字处理类
        /// </summary>
        public IFizzBuzzWhizz NextFlow { get; set; }

        /// <summary>
        /// 处理特殊数字
        /// </summary>
        /// <param name="number">数字</param>
        /// <param name="isHandle">是否被处理</param>
        public void Process(int number, bool isHandle = false)
        {
            //如果某个数字包含当前的特殊数字,那么就执行当某个数字包含当前特殊数字的事件,并且。终止往后调用。
            if (number.ToString(CultureInfo.InvariantCulture).Contains(this.SpecialNumber.ToString(CultureInfo.InvariantCulture)))
            {
                if (this.ContainsSpecialNumberAction != null)
                    this.ContainsSpecialNumberAction(number);
                return;
            }
            //如果某个数字是当前特殊数字的倍数的时候,就执行是倍数时要执行的事件。并且标记ishandle为true。传递到下一个流程
            if (number % this.SpecialNumber == 0)
            {
                if (this.MultipleAction != null)
                    this.MultipleAction(number, isHandle);
                isHandle = true;
            }
            //调用下一个流程的方法
            if (this.NextFlow != null)
                this.NextFlow.Process(number, isHandle);
        }
    }
View Code
/// <summary>
    /// 第三个特殊数字处理类
    /// </summary>
    public class Whizz : IFizzBuzzWhizz
    {
        /// <summary>
        /// 构造一个第三个特殊数字处理类
        /// </summary>
        /// <param name="specialNumber">特殊数字</param>
        /// <param name="nextFlow">下一个流程,这里默认是null,因为目前就三种情况</param>
        /// <param name="multipleAction">当某个数字是特殊数字的倍数时,所要触发的事件</param>
        /// <param name="neverHandleAction">当从来没用被任何一个特殊数字类处理过的时候要执行事件(这里就是指,这个数字既不是第一个特殊数字的倍数,也不是第二个特殊数字的倍数,更不是第三个特殊数字的倍数)</param>
        public Whizz(int specialNumber, IFizzBuzzWhizz nextFlow, Action<int, bool> multipleAction, Action<int, bool> neverHandleAction)
        {
            this.SpecialNumber = specialNumber;
            this.NextFlow = nextFlow;
            this.MultipleAction = multipleAction;
            this.NeverHandleAction = neverHandleAction;
        }

        public Whizz(int specialNumber, Action<int, bool> multipleAction, Action<int, bool> neverHandleAction)
            : this(specialNumber, default(IFizzBuzzWhizz), multipleAction, neverHandleAction)
        {
        }

        public Whizz(int specialNumber)
            : this(specialNumber, default(IFizzBuzzWhizz), (number, isHandle) => Console.Write("{0}Whizz", isHandle ? string.Empty : "\r\n"), (number, isHandle) => Console.Write("{0}{1}", isHandle ? string.Empty : "\r\n", number))
        {
        }

        public Action<int, bool> MultipleAction { get; set; }

        public Action<int, bool> NeverHandleAction { get; set; }

        public int SpecialNumber { get; set; }

        public IFizzBuzzWhizz NextFlow { get; set; }

        public void Process(int number, bool isHandle)
        {
            if (number % this.SpecialNumber == 0)
            {
                if (this.MultipleAction != null)
                    this.MultipleAction(number, isHandle);
                isHandle = true;
            }
            if (!isHandle)
            {
                if (this.NeverHandleAction != default(Action<int, bool>))
                    this.NeverHandleAction(number, isHandle);
            }
            if (this.NextFlow != null)
                this.NextFlow.Process(number, isHandle);
        }
    }
View Code
/// <summary>
    /// 游戏控制者
    /// </summary>
    public class GameController
    {
        public string StartGame(int players, params int[] numbers)
        {
            var fizz = new Fizz(numbers[0]);
            var buzz = new Buzz(numbers[1]);
            var whizz = new Whizz(numbers[2]);
            fizz.NextFlow = buzz;
            buzz.NextFlow = whizz;
            var result = new StringBuilder();
            for (var i = 1; i <= players; i++)
            {
                fizz.Process(i);
            }
            return result.ToString();
        }
    }
View Code

 

 

下面附上我的代码。欢迎大家提供不同的面向对象设计思路。

https://github.com/freestyleSago/FizzBuzzWhizz.git

posted @ 2014-05-06 16:12  Sago  阅读(633)  评论(3编辑  收藏  举报