设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

我是如何将3000行代码重构成15行的

2014-12-2 15:46| 发布者: joejoe0332| 查看: 4112| 评论: 0|原作者: TECHUG|来自: 程序师

摘要: 如果你认为这是一个标题党,那么我真诚的恳请你耐心的把文章的第一部分读完,然后再下结论。如果你认为能够戳中您的G点,那么请随手点个赞。


少用代码生成器

我们来分析一下,为什么我之前的前辈会写出上面的代码。我归结起来有以下几点:

  • 因为使用了动软代码生成器,生成代码方便,就没多想了。
  • 三层架构的概念倒是了解了,但是没有去深入思考就拿来应用
  • 遇到重复的代码,没有重构的概念,这是思想的问题——思想比你的能力重要

至 今为止,还是很多人使用代码生成器,那么我们应该怎么对待这个问题呢。我认为,代码生成器确实可以减少你不少工作,但是少用,那些重复性的工作,除了部分 确实是没有办法的,其他大部分都是可以通过框架解决的,举例来说,像三层架构,真正需要用到代码生成器的,也就是Model类而已,其他的完全可以在框架 中完成。因此你要竭尽全力的思考怎么在框架中来减少你的重复性工作,而不是依赖于代码生成器

另外,如果你还是在用相关的代码生成工具,请重新定义“动软代码生成器”的代码模板,自己写一个模板;或者使用CodeSmith来完全制定自己的代码生成,因为动软给的代码模板真心乱,比如下面这段代码:

for (int n = 0; n < rowsCount; n++)
{
	model = new DBAccess.Model.eventweek();
	if(dt.Rows[n]["GroupNo"].ToString()!="")
	{
		model.GroupNo=int.Parse(dt.Rows[n]["GroupNo"].ToString());
	}
	if(dt.Rows[n]["Week0"].ToString()!="")
	{
		model.Week0=int.Parse(dt.Rows[n]["Week0"].ToString());
	}
	if(dt.Rows[n]["Week1"].ToString()!="")
	{
		model.Week1=int.Parse(dt.Rows[n]["Week1"].ToString());
	}
}

首先,你就不能用 var row=dt.Rows[n] 替代吗?其次,直接用int.Parse效率多低?再次,dt.Rows[n]["Week0"]NULL怎么办?

不要重复发明轮子

我们再来看看其他的一些代码:

public List<string> GetDevices(string dev){
	List<string> devs=new List<string>();

	int start=0;
	for(int i=0;i<dev.Length;i++){
		if(dev[i]=='^'){
			devs.Add(dev.SubString(start,i));
			start=i+1;
		}
	}

	return devs;
}

有没有很眼熟,没错,这就是对String.Split()函数的简单实现。我的前辈应该是从c++程序员转过来的,习惯了各种功能自己实现一遍,但是他忽略了C#的很多东西。我们不去评判这段代码的优劣,而实际上他在很长一段时间都运行得很好。我们来看看使用这一段代码有什么不好的地方:

  • 重复发明轮子。花费了额外的时间,函数的健壮性和很差
  • 可读性差。其实是一个很简单的功能,但是用上了这么一段函数,起初我还以为有什么特别的功能。

那么,我们应该怎样去避免重复发明轮子呢?我从个人的经历来提出以下几点,希望能够对各位有所帮助:

  • 了解你所学的编程语言的特性。你可以看一本基础的入门书籍,把所有的特性浏览一遍,或者上MSDN,把相关的内容过一遍。
  • 在你决定动手发明一个轮子之前,先搜索一下现成的解决方案。你还可以到CodeProject、GitHub之类的网站搜索一下。在知乎上有很多大牛其实都在批评,为什么你提问之前,不能首先去搜一下是否有现成的答案,反而指责没有回答他的问题。
  • 你有一定的基础之后,还应该去读一下相关的经典书籍,深入了解其中的原理。比如,你觉得你有一定的基础了,我建议你去吧《CLR Via C#》多读几遍,你了解原理越多,你越是能够利用这编程语言的特性,从而来实现原本那些你认为要靠自己写代码的功能。

这 里我再举一个我自己的例子。在我现有的程序中,我发现我需要越来越多的线程来执行一些简单的任务,比如在每天检测一下硬盘是否达到90%了,每天9点要控 制一下空调的开启而在网上6点的时候把空调关掉。线程使用越来越多,我越是觉得浪费,因为这些现场仅仅只需完成一次或者有限的几次,大部分时间都是没有意 义的,那么怎么办呢?我决定自己写一个任务类,来完成相关的事情。说干就干,我很快把这个类写出来了。

public abstract class MissionBase : IMission
{
    private DateTime _nextExecuteTime;
    protected virtual DateTime[] ExecuteTimePoints { get; private set; }
    protected virtual int IntervalSeconds { get; private set; }
    protected IEngine Engine { get; private set; }

    public bool IsCanceled{get{……}}
    public bool IsExecuting{get{……}}
    public bool IsTimeToExecute{get{……}}

    public abstract bool Enable { get; }
    public abstract string Name { get; }

    protected MissionBase(IEngine engine)
    {
        ExecuteTimePoints = null;//默认采用间隔的方式
        IntervalSeconds = 60 * 60;//默认的间隔为1个小时

        Engine = engine;
    }

    /// 任务的执行方法
    public void Done()
    {
        if (Interlocked.CompareExchange(ref _isExecuting, 1, 0) == 1) return;

        try
        {
			……
        }
        finally
        {
            Interlocked.CompareExchange(ref _isExecuting, 0, 1);
        }
    }
	
	///实际方法的执行
    protected abstract void DoneReal();
}

但是,实际上这个任务方法,并不好用,要写的代码不少,而且可靠性还没有保障。当然,我可以继续完善这个类,但是我决定搜索一下是否还有其他的方法。直到有一天,我再次阅读《CLR Via C#》,看到线程这一章,讲到了System.Threading.Timer以及ThreadPool类时,我就知道了,使用Timer类完全可以解决我的这个用尽量少的线程完成定时任务的问题

因为从原理上来说,Timer类无论你声明了多少个,其实就只有一个线程在执行。当你到了执行时间时,这个管理线程会用ThreadPool来执行Timer中的函数,因为使用的ThreadPool,执行完成之后,线程就马上回收了,这个其实就完全实现了我所需要的功能。


酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部