设计模式系列之状态模式(2)_System

前言

如何增加代码行数,设计模式应该是一个不错的选择。后续设计模式的内容会持续更新,欢迎关注。

语言使用的是C#,纯面向对象的语言。笔者比较喜欢C#,C#的语法糖和设计都很棒,其他语言同理,语言只是工具。

设计模式的目的

增加代码量是最不重要的目的,其真正的目的是符合软件设计原则:

  1. 开闭原则
  2. 依赖倒置原则
  3. 接口隔离原则
  4. 单一职责原则
    其中的开闭原则是最重要的,大部分的设计模式也在解决这个问题。

不用设计模式

设计一个投票系统。要求如下:

  1. 投票一次,表示投票成功
  2. 投票在3次以内,提示不要重复投票
  3. 3次到7次,为恶意投票,删除用户
  4. 超过8次(含),加入黑名单,禁止登陆系统。

代码实现

代码很简单。判断投票数,对不同状态的处理。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class VoteManager
    {
        private Dictionary<String, String> dictionaryVote = new Dictionary<string, string>();
        private Dictionary<String, int> dictionaryVoteCount = new Dictionary<string, int>();

        private int count = 0;
 
        public void Vote(String user, String voteItem)
        {
            bool contain = dictionaryVoteCount.ContainsKey(user);
            if (!contain)
            {
                dictionaryVoteCount[user] = 0;
            }

            count = dictionaryVoteCount[user] + 1;
            dictionaryVoteCount[user] = count;
            if (count == 1)
            {
                Console.WriteLine("投票成功");
                dictionaryVote.Add(user, voteItem);
            } else if(count > 1 && count < 3) {
                Console.WriteLine("请不要重复投票");
            } else if (count >= 3 && count < 8) {
                dictionaryVote.Remove(user);
                Console.WriteLine("存在恶意投票行为,取消投票资格");
            } else if (count >= 8) {
                Console.WriteLine("加入黑名单,禁止登陆系统");
            }
        }
    }
}

代码存在的问题

  1. 代码量好像有点少
  2. 大量的if/else语句,违反开闭原则

状态模式

使用设计模式基本都能解决第一个问题,能增加很多的代码量。对于第二个问题,需要考虑使用什么模式,因为和状态相关,各个状态之间不可替换,所以选择状态模式。

定义

允许一个对象在其内部状态改变的时候改变它的行为,对象看起看来似乎修改了他的类。

类图设计

设计模式系列之状态模式(2)_System_02

代码实现

上下文
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class VoteManagerContext
    {
        // 投票状态
        private VoteState voteState;

        // 投票用户 投票选项
        private Dictionary<String, String> dictionaryVote = new Dictionary<String, String>();

        // 投票用户 投票数量
        private Dictionary<String, int> dictionaryVoteCount = new Dictionary<string, int>();

        //保存投票的数量
        private int count = 0;

        public  Dictionary<String, String> getDictionaryVote()
        {
            return dictionaryVote;
        }

        public void Vote(String user, String item)
        {
            bool contain = dictionaryVoteCount.ContainsKey(user);
            if (!contain)
            {
                dictionaryVoteCount[user] = 0;
            }
            count = dictionaryVoteCount[user] + 1;
            dictionaryVoteCount[user] = count;
            //状态处理
            if (count == 1)
            {
                voteState = new NormalVoteState();
            } else if(count > 1 && count< 3) {
                voteState = new RepeatNoteState();
            } else if (count >= 3 && count< 8) {
                voteState = new SpiteVoteState();
             } else if (count >= 8)  {
                voteState = new BlackVoteState();
            }
            voteState.Vote(user, item, this);
        }
    }
}
状态接口
namespace ConsoleApp1
{
    internal interface VoteState
    {
        public void Vote(string user, string item, VoteManagerContext voteManagerContext);
    }
}
具体实现

正常投票状态

namespace ConsoleApp1
{
    internal class NormalVoteState : VoteState
    {
        public void Vote(string user, string item, VoteManagerContext voteManagerContext)
        {
            Console.WriteLine("投票成功");
            voteManagerContext.getDictionaryVote().Add(user, item);
        }
    }
}

重复投票状态

namespace ConsoleApp1
{
    internal class RepeatNoteState : VoteState
    {
        public void Vote(string user, string item, VoteManagerContext voteManagerContext)
        {
            Console.WriteLine("请不要重复投票");
        }
    }
}

恶意投票状态

namespace ConsoleApp1
{
    internal class SpiteVoteState : VoteState
    {
        public void Vote(string user, string item, VoteManagerContext voteManagerContext)
        {
            bool contain = voteManagerContext.getDictionaryVote().ContainsKey(user);
            if (contain)
            {
                voteManagerContext.getDictionaryVote().Remove(user);
            }
            Console.WriteLine("存在恶意投票行为,取消投票资格");
        }
    }
}

黑名单投票状态

namespace ConsoleApp1
{
    internal class BlackVoteState : VoteState
    {
        public void Vote(string user, string item, VoteManagerContext voteManagerContext)
        {
            Console.WriteLine("加入黑名单,禁止登陆系统");
        }
    }

}

客户端代码

using ConsoleApp1;

public class ConsoleApp
{
    public static void Main(String[] atgs)
    {
        Console.WriteLine("不用模式的运行结果:");
        VoteManager voteManager = new VoteManager();
        for (int i = 0; i < 10; i++)
        {
            voteManager.Vote("Burning", "sxy");
        }

        Console.WriteLine("\n");
        Console.WriteLine("使用装填模式的运行结果:");
        VoteManagerContext vmc = new VoteManagerContext();
        
       for (int i = 0; i < 10; i++)
        {
            vmc.Vote("Burning", "sxy");
        }

    }
}

最终运行结果:

设计模式系列之状态模式(2)_状态模式_03


结果是完全一样的。但后者的灵活性比前者好太多了。后者的扩展性比前者好很多,但依然存在问题,依然又if/else没有被消灭,可有办法解决哪?下一篇文章来彻底消灭if/else。

写在最后

本文的Java版本可参考设计模式之状态模式。

设计模式,讲究面向接口而不是具体的实现。

公众号

更多内容,欢迎关注我的微信公众号: 无情剑客。

设计模式系列之状态模式(2)_System_04