结对编程代码分析


正文

功能要求

实现登录功能,能够储存多个账户密码。有三种不同的登陆模式,可以分别生成对应的题目并且输出到文档之中。出题有查重功能,同一个人出的题不能重复。

功能实现

这位同学使用了一个状态模式去实现几种不同的登录状态(以及正在登录的状态),由一个指令接受类在命令行接受命令,在这个环境经过内建命令的处理,然后发送给当前状态之中。
登录、输出两个模块是独立的。各自独立的几个模块通过发布订阅模式来联系。他实现了一个事件中心,实现了不同的类均可以通过事件中心单例去订阅和发布事件。
其中,命令接受、事件中心、输出以及登录几个模块是单例的。

具体实现

事件中心

namespace EventSystem

{

    // 标准的回调函数委托接口

    public interface IEventCallBack

    { }

  

    // 回调函数事件的两个重载

    public class EventCallBack : IEventCallBack

    {

        public Action actions;

        public EventCallBack(Action action)

        {

            actions += action;

        }

    }

    public class EventCallBack<T> : IEventCallBack

    {

        public Action<T> actions;

  

        public EventCallBack(Action<T> action)

        {

            actions += action;

        }

    }

  
  

    // 本项目的事件中心,实现完全解耦合的发布订阅模式

    public class EventCenter

    {

        // 单例

        private static EventCenter? instance = null;

  

        // 事件管理字典

        private Dictionary<EventType, IEventCallBack> _events =

            new Dictionary<EventType, IEventCallBack>();

  

        private EventCenter()

        {

            // do nothing

        }

        public static EventCenter GetInstance()

        {

            if(instance==null)

            {

                instance = new EventCenter();

            }

            return instance;

        }

  

        /// <summary>

        /// 订阅事件

        /// </summary>

        /// <param name="type">事件类型</param>

        /// <param name="action">以委托形式传递的回调函数</param>

        public void EventSubscribe(EventType type, Action action)

        {

            if(_events.ContainsKey(type))

            {

                (_events[type] as EventCallBack).actions += action;

            }

            else

            {

                _events.Add(type, new EventCallBack(action));

            }

        }

        public void EventSubscribe<T>(EventType type, Action<T> action)

        {

            if(_events.ContainsKey(type))

            {

                (_events[type] as EventCallBack<T>).actions += action;

            }

            else

            {

                _events.Add(type, new EventCallBack<T>(action));

            }

        }

        /// <summary>

        /// 退订事件

        /// </summary>

        /// <param name="type">事件类型</param>

        /// <param name="action">以委托形式传递的回调函数</param>

        public void EventUnsubscribe(EventType type, Action action)

        {

            if (_events.ContainsKey(type))

            {

                (_events[type] as EventCallBack).actions -= action;

            }

        }

        public void EventUnsubscribe<T>(EventType type, Action<T> action)

        {

            if(_events.ContainsKey(type))

            {

                (_events[type] as EventCallBack<T>).actions -= action;

            }

        }

        /// <summary>

        /// 发布事件

        /// </summary>

        /// <param name="type">事件类型</param>

        public void EventTrigger(EventType type)

        {

            if (_events.ContainsKey(type))

            {

                (_events[type] as EventCallBack).actions?.Invoke();

            }

        }

        /// <summary>

        /// 发布事件

        /// </summary>

        /// <param name="type">事件类型</param>

        /// <param name="args">传递参数</param>

        public void EventTrigger<T>(EventType type, T args)

        {

            if(_events.ContainsKey(type))

            {

                (_events[type] as EventCallBack<T>).actions?.Invoke(args);

            }

        }

  

        /// <summary>

        /// 清空事件列表

        /// </summary>

        public void Clear()

        {

            _events.Clear();

        }

    }

}

状态管理

public class StateManager

{

    // 当前生效的状态

    private IState _state ;

    // 当前登录的用户名

    public string Username;

    // 该用户的出题历史

    public HashSet<string> UserTestHistory = new HashSet<string>();

    // 该用户的出题总数

    private int _count=0;

  

    // 可能存在的四种状态

    private LoginState _loginState = new LoginState();

    private PrimaryState _primaryState = new PrimaryState();

    private JuniorState _juniorState = new JuniorState();

    private SeniorState _seniorState = new SeniorState();

  
  

    // 构造函数

    public StateManager()

    {

        // 初始状态为待登录状态

        _state = _loginState;

        _state.Handle(this);

        EventCenter.GetInstance().EventSubscribe<Account>(

            EventType.LoginSuccess,

            (account) => LoginSuccess(account)

        );

    }

    // 切换当前状态

    public void StateSwitch(Grade type)

    {

        switch(type)

        {

            case Grade.None:

                _state = _loginState;

                break;

            case Grade.Primary:

                _state = _primaryState;

                break;

            case Grade.Junior:

                _state = _juniorState;

                break;

            case Grade.Senior:

                _state = _seniorState;

                break;

            default:

                break;

        }

        _state.Handle(this);

    }

  

    /// <summary>

    /// 主要操作类接收指令的入口

    /// </summary>

    /// <param name = "command">命令行读取入的指令</param>

    public void CommandRecv(string command)

    {

        _state.CommandRecv(command);

    }

  

    // 登录成功后的处理

    public void LoginSuccess(Account account){

        Username = account.UserName;

        // 检查是否已经存在对应用户文件并进行创建

        if( Directory.Exists(@"./File/"+Username) == true)

        {

            // 存在用户文件夹

            if(!File.Exists(@"./File/"+Username+@"/"+Username+".txt"))

            {

                FileStream fs = new FileStream(@"./File/"+Username+@"/"+Username+".txt", FileMode.Append);

                StreamWriter wr = null;

                wr = new StreamWriter(fs);

                wr.WriteLine("0");

                wr.Close();

            }

        }

        else

        {

            // 创建一个记录为0条的用户出题历史

            Directory.CreateDirectory(@"./File/"+Username);

            FileStream fs = new FileStream(@"./File/"+Username+@"/"+Username+".txt", FileMode.Append);

            StreamWriter wr = null;

            wr = new StreamWriter(fs);

            wr.WriteLine("0");

            wr.Close();

        }

  

        // 读取用户出题数据

        StreamReader rd = File.OpenText(@"./File/"+Username+@"/"+Username+".txt");

        string s = rd.ReadLine();

        // 出题历史的总条数

        _count = int.Parse(s);

  

        for (int i = 0; i < _count; i++)  //读入数据并赋予数组

        {

            string line = rd.ReadLine();

            UserTestHistory.Add(line);

        }          

        rd.Close();

    }

  

    // 保存出题历史

    public void SaveHistory()

    {

        System.IO.File.WriteAllText(@"./File/"+Username+@"/"+Username+".txt", string.Empty);

        FileStream fs = new FileStream(@"./File/"+Username+@"/"+Username+".txt",FileMode.Append);

        StreamWriter wr = null;

        wr = new StreamWriter(fs);

        wr.WriteLine(_count);

        foreach(string test in UserTestHistory)

        {

            wr.WriteLine(test);

        }

        wr.Close();

    }

  

    /// <summary>

    /// 检查试题是否重复

    /// </summary>

    public bool AddTestHistory(string test)

    {

        string code = MD5.GetInstance().StringToMD5_UTF8(test);

        if(UserTestHistory.Contains(code))

        {

            return false;

        }

        _count++;

        UserTestHistory.Add(code);

        return true;

    }

}

运行效果

结对编程代码分析

结对编程代码分析

结对编程代码分析

优点

系统的结构有设计,易于拓展,条例相对清晰,不同模块之间耦合度低(发布订阅模式),便于后期代码维护和拓展。
注释非常全面,许多跨类调用的函数都有精确到每个参数的注释,便于代码阅读。
命名比较符合c#的命名规则(参考网络上的谷歌开源c#代码规范),阅读起来比较方便。
有基于安全性考虑而采用的哈希算法加密。

缺点

代码过多,有一些功能稍显无用。
单例模式过多,许多独立的模块都是单例,其中一些是可以改善的。
资源相对开销较大。
对于结构体和接口的使用,一部分仍存在一些问题,需要重构优化一下。
有的注释比较繁琐,不够精炼,应当注意注释的简洁明了。
没有使用数据库,而是在本地用字典保存用户信息,这一部分值得拓展一下。
虽然考虑到了安全性以及系统的结构,但是没有充分考虑到应用过程中的数据传输结构,数据打包方式等等。在真正把它做成实用的系统的时候,可能还需要大规模的重构。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/289298.html

(0)
上一篇 2022年9月14日
下一篇 2022年9月14日

相关推荐

发表回复

登录后才能评论