用Helper对类的行为进行修饰以便复用(附:外三篇)

本文是 代码“中间地带”的封装与复用 的后续。

 

咱不谈设计模式这种“高档”货,也不谈M××,只谈怎么消除Copy+Paste,消除拖窗体设置属性这类耗时、易错的动作。

前些天和我徒弟聊天,他沾沾自喜的说他一天要写500行css,俺打击他说,啥时候他一天写到100行时才算悟了。

 

写代码就是一个由多到少的过程:

(1)见山是山时,一天能写1000行,大量的Copy+Paste,这叫代码迷宫

(2)见山不是山时,一天能写500行,Copy+Paste变成了大量的设计模式,这叫类的迷宫,Java程序尤其擅长这个,搞得我现在不敢看Java程序了。开个玩笑,重构到模式,实际上是从一种垃圾(代码迷宫)重构到另一种垃圾(类的迷宫)

(3)见山还是山时,一天能写100行,回归本源

 

先描述一个很常见的 Copy+Paste 场景:为客户端程序添加NotifyIcon,当关闭窗体时,窗体消失,缩小到托盘,双击托盘图标,则窗体又重现。

对于这一需求,msdn 的样例如下:

ContractedBlock.gif ExpandedBlockStart.gif Code
using System;
using System.Drawing;
using System.Windows.Forms;

public class Form1 : System.Windows.Forms.Form
{
    
private System.Windows.Forms.NotifyIcon notifyIcon1;
    
private System.Windows.Forms.ContextMenu contextMenu1;
    
private System.Windows.Forms.MenuItem menuItem1;
    
private System.ComponentModel.IContainer components;

    [STAThread]
    
static void Main() 
    {
        Application.Run(
new Form1());
    }

    
public Form1()
    {
        
this.components = new System.ComponentModel.Container();
        
this.contextMenu1 = new System.Windows.Forms.ContextMenu();
        
this.menuItem1 = new System.Windows.Forms.MenuItem();

        
// Initialize contextMenu1
        this.contextMenu1.MenuItems.AddRange(
                    
new System.Windows.Forms.MenuItem[] {this.menuItem1});

        
// Initialize menuItem1
        this.menuItem1.Index = 0;
        
this.menuItem1.Text = "E&xit";
        
this.menuItem1.Click += new System.EventHandler(this.menuItem1_Click);

        
// Set up how the form should be displayed.
        this.ClientSize = new System.Drawing.Size(292266);
        
this.Text = "Notify Icon Example";

        
// Create the NotifyIcon.
        this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components);

        
// The Icon property sets the icon that will appear
        
// in the systray for this application.
        notifyIcon1.Icon = new Icon("appicon.ico");

        
// The ContextMenu property sets the menu that will
        
// appear when the systray icon is right clicked.
        notifyIcon1.ContextMenu = this.contextMenu1;

        
// The Text property sets the text that will be displayed,
        
// in a tooltip, when the mouse hovers over the systray icon.
        notifyIcon1.Text = "Form1 (NotifyIcon example)";
        notifyIcon1.Visible 
= true;

        
// Handle the DoubleClick event to activate the form.
        notifyIcon1.DoubleClick += new System.EventHandler(this.notifyIcon1_DoubleClick);

    }

    
protected override void Dispose( bool disposing )
    {
        
// Clean up any components being used.
        if( disposing )
            
if (components != null)
                components.Dispose();            

        
base.Dispose( disposing );
    }

    
private void notifyIcon1_DoubleClick(object Sender, EventArgs e) 
    {
        
// Show the form when the user double clicks on the notify icon.

        
// Set the WindowState to normal if the form is minimized.
        if (this.WindowState == FormWindowState.Minimized)
            
this.WindowState = FormWindowState.Normal;

        
// Activate the form.
        this.Activate();
    }

    
private void menuItem1_Click(object Sender, EventArgs e) {
        
// Close the form, which closes the application.
        this.Close();
    }
}

 

于是,我们开发Client程序时,当需要这一功能,就把这样的代码复制过来,改吧改吧就完成了。

复制粘贴很恶心,一次两次还好,次数多了自己就烦了。并且这样一来,导致代码量膨胀——功能一多,一个Form的代码量就近千行,很不方便测试和维护。因此,有必要进行抽象和复用。

这种抽象,属于对类的局部行为进行修饰(设计模式放在括号里谈,不想看的可以忽略——它不同于Mediator,也不同于Wrapper,一时也想不出好的名字),就叫Helper了。单纯的Helper又体现不出具体的意图,俺就命名为FormConfig。下面是 FormConfig 的代码:

ContractedBlock.gif ExpandedBlockStart.gif Code
    public class FormConfig
    {
        
public NotifyIcon NotifyIcon { get;private set; }
        
public ContextMenuStrip NotifyIconMenuStrip { get;private set; }
        
public Boolean EnableFormExit { getset; }

        
private Form Form { getset; }

        
/// <summary>
        
/// 为窗体添加 NotifyIcon。并为其配置默认的右键菜单。双击NotifyIcon,激活窗体。
        
/// </summary>
        
/// <param name="form">窗体</param>
        public void AttachNotifyIcon(Form form)
        {
            AttachNotifyIcon(form, 
nullnull, CreateNotifyIconMenuStrip());
        }

        
/// <summary>
        
/// 为窗体添加 NotifyIcon。双击NotifyIcon,激活窗体。
        
/// </summary>
        
/// <param name="form">窗体</param>
        
/// <param name="title">NotifyIcon 的 Title,若为空,则使用窗体的 Text 作为 NotifyIcon 的 Title </param>
        
/// <param name="icon">NotifyIcon 的 图标,若为空,则使用窗体的 图标作为 NotifyIcon 的图标 </param>
        
/// <param name="notifyIconMenuStrip">NotifyIcon 的右键菜单</param>
        public void AttachNotifyIcon(Form form, String title, Icon icon, ContextMenuStrip notifyIconMenuStrip)
        {
            
if (form == nullthrow new ArgumentNullException("form");
            
if (notifyIconMenuStrip == nullthrow new ArgumentNullException("notifyIconMenuStrip");

            
if (NotifyIcon == null) NotifyIcon = new NotifyIcon();
            
if (NotifyIconMenuStrip == null) NotifyIconMenuStrip = CreateNotifyIconMenuStrip();
            NotifyIcon.ContextMenuStrip 
= NotifyIconMenuStrip;
            NotifyIcon.Text 
= title == null ? form.Text : title;
            NotifyIcon.Icon 
= icon == null? form.Icon : icon;
            NotifyIcon.DoubleClick 
+= new EventHandler(NotifyIcon_DoubleClick);
            Form 
= form;
            Form.FormClosing 
+= new FormClosingEventHandler(Form_FormClosing);
        }

        
private void NotifyIcon_DoubleClick(object sender, EventArgs e)
        {
            ShowMainForm();
        }

        
private ContextMenuStrip CreateNotifyIconMenuStrip()
        {
            ToolStripMenuItem itemShowForm 
= new ToolStripMenuItem("显示主窗口");
            ToolStripMenuItem itemCloseForm 
= new ToolStripMenuItem("退出");
            itemShowForm.Click 
+= new EventHandler(ItemShowForm_Click);
            itemCloseForm.Click 
+= new EventHandler(ItemCloseForm_Click);
            ContextMenuStrip cms 
= new ContextMenuStrip();
            cms.Items.Add(itemShowForm);
            cms.Items.Add(itemCloseForm);
            
return cms;
        }

        
private void ItemShowForm_Click(object sender, EventArgs e)
        {
            ShowMainForm();
        }

        
private void ItemCloseForm_Click(object sender, EventArgs e)
        {
            
if(Form!=null)
            {
                EnableFormExit 
= true;
                Form.Close();
                NotifyIcon.Visible 
= false;
            }
        }

        
private void Form_FormClosing(object sender, FormClosingEventArgs e)
        {
            
if (!EnableFormExit)
            {
                e.Cancel 
= true// 取消关闭窗体
                Form.Hide();
                Form.ShowInTaskbar 
= false;
                NotifyIcon.Visible 
= true;//显示托盘图标
            }
        }

        
private void ShowMainForm()
        {
            
if (Form == nullreturn;

            Form.Show();
            
if (Form.WindowState == FormWindowState.Minimized)
                Form.WindowState 
= FormWindowState.Normal;
            Form.Activate();
        }
    }

 

使用起来很简单:

ContractedBlock.gif ExpandedBlockStart.gif Code
    public partial class MainForm : Form
    {
        
private FormConfig FormConfig { getset; }

        
public MainForm()
        {
            InitializeComponent();
        }

        
private void MainForm_Load(object sender, EventArgs e)
        {
            FormConfig 
= new FormConfig();
            FormConfig.AttachNotifyIcon(
this);
        }
    }

 

其实这个还可以简化,因为毕竟还要声明一个FormConfig,再new一个,再Attach一下子,3行代码。进一步偷懒的话可以设计一个扩展方法,然后把FormConfig实例放在一个公共对象中进行管理,当Form退出时,再在公共对象中置空FormConfig。就不写代码了,简化到目前这个地步,俺已经满足了。

 

== 附外3篇 ==

 

下面这两篇和上面的这篇都是昨天晚上写的。第一篇是对这一段时间代码整理的总结,有点私人化。第二篇是讲通用验证码识别的一个思路,不是完整的文章,同时……又涉及点技术秘密,没办法完全透露。再附一篇完全搞笑的。

 

附1:代码整理的总结

 

搞了四个月的工作室,失败了,散了,好在成本严格控制住了,也没亏多少,最大的收获就是得到了证实——此路不通。

还是坚持当IT宅男,坚持向产品和高端转型,增强竞争优势。我希望投资回报是一条上升的线,而不是一条下降的线。

 

于是最近做的事情主要是整理代码和复习和学习数学。今后将玩数学了,主要做数学密集的应用。(看现在经济形势,10年内会新出现7000万白领,会减少7000万蓝领,蓝领的平均工资将于白领持平。国内又提供不了这么多白领岗位,IT界的竞争将无比的残酷。作为没有组织做后盾的IT宅男,俺必须早点布局。好在现在大部分大学生大学都是白混的,是数学白痴,和以前的俺一样)。

 

一、应用结构

 

1、  采用C-S结构,关键部分的计算放在S端,方便升级、收费。今后将引入P2P

2、  自己用的话,用WPF开发界面,客户用的,用Winform开发。核心代码尽量与UI无关。

3、  将不再承接Web开发为主的项目,不承接数据库开发为主的项目

 

二、项目结构

 

1、微观结构

 

bin

lib

release

src

 

2、宏观结构

 

 

1Orc基础库主要封装一些常用的类、扩展方法、Mediator,以及一些基础设施,顺带储存自己用的snippets

 

 

嘿嘿,俺自定义的snippet只有一个:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
      public event EventHandler<$YourEventArgs$> $YourEventHandler$;
      
      
protected virtual void On$YourEventHandler$($YourEventArgs$ e)
      {
          EventHandler
<$YourEventArgs$> handler = $YourEventHandler$;
          
if (handler != null)
          {
              handler(
this, e);
          }
      }
      $end$

 

2OrcSmart库计划包括

aOrc.SmartImage,对常用的图像处理、分析、识别算法进行封装,基于AForge.NetOpenCV进行开发,并新添一些这两个库尚未实现的算法。目前基本成型。

bOrc.SmartText,对常用的文本分析,NLP算法进行封装,这个库现在还是一个空架子,还未行动。

Orc.SmartCore被我归入Orc基础库里面,这个主要实现常用统计计算和机器学习算法。

 

3Orc协议库对常用协议进行实现与封装,目前实现了QQ2005-2007的协议,YMsg协议,封装了MSNP协议。今后将主要针对基于httpWeb应用进行封装。

 

4OrcEntity库,封装常用实体类。

 

5Forsaken库主要针对3D应用,基于XNA,目前还是空架子,还未行动(一没时间,二外部环境还不成熟)。嘿嘿,主要目标是3D仿真。

 

三、第三方库选择:

(1)       使用nunit 进行单元测试(nunitvs自带的单元测试好用很多)

(2)       使用log4net 记录日志

(3)       使用protobuf 进行序列化

(4)       图像处理库:AForge.NetOpenCVEmgu CV

(5)       数学库:MathNet.Iridium

 

附2:通用验证码识别的一个思路

 

要实现通用的验证码程序,我认为应该具备以下2点:

(1)       不需要切割

(2)       不需要分离背景和前景

 

下面是我的思路:

(1)       边缘检测获得边缘

(2)       计算样本的ShapeContext,因为要考虑到干扰线,ShapeContext没法归一化

(3)       计算测试图片的ShapeContext(也可以是其它的描述子,但我感觉对于验证码来说,ShapeContext更好用一些,抗干扰能力更强一些。也可以计算不同Scale下的ShapeContext,来解决样本和测试图片中字符大小不一致的问题)

(4)       将测试图片的ShapeContext存入多维索引中,便于查询

(5)       对于样本,设定一个匹配的阈值,为每个点寻找测试图片中的匹配点(每个寻找2-3个匹配点),这样,所有的匹配点会在2D空间内呈现一种分布,这种分布会有0个或数个聚集区,每一个聚集区就是一个候选区,通过聚类算法寻找聚集区

(6)       假定图片中有一个字符W,这个字符既可以匹配W,又可以匹配V,甚至能匹配IL这两个字符,因此应该设计一个筛选算法

 

附3:江湖

 

转载于:https://www.cnblogs.com/xiaotie/archive/2009/11/12/1601456.html

递归下降分析法 一、实验目的: 根据某一文法编制调试递归下降分析程序,以便对任意输入的符号串进行分析。本次实验的目的主要是加深对递归下降分析法的理解。 二、实验说明 1、递归下降分析法的功能 词法分析器的功能是利用函数之间的递归调用模拟语法树自上而下的构造过程。 2、递归下降分析法的前提 改造文法:消除二义性、消除左递归、提取左因子,判断是否为LL(1)文法, 3、递归下降分析法实验设计思想及算法 为G的每个非终结符号U构造一个递归过程,不妨命名为U。 U的产生式的右边指出这个过程的代码结构: (1)若是终结符号,则和向前看符号对照, 若匹配则向前进一个符号;否则出错。 (2)若是非终结符号,则调用与此非终结符对应的过程。当A的右部有多个产生式时,可用选择结构实现。 三、实验要求 (一)准备: 1.阅读课本有关章节, 2.考虑好设计方案; 3.设计出模块结构、测试数据,初步编制好程序。 (二)上课上机: 将源代码拷贝到机上调试,发现错误,再修改完善。第二次上机调试通过。 (三)程序要求: 程序输入/输出示例: 对下列文法,用递归下降分析法对任意输入的符号串进行分析: (1)E->eBaA (2)A->a|bAcB (3)B->dEd|aC (4)C->e|dc 输出的格式如下: (1)递归下降分析程序,编制人:姓名,学号,班级 (2)输入一以#结束的符号串:在此位置输入符号串例如:eadeaa# (3)输出结果:eadeaa#为合法符号串 注意: 1.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好); 2.对学有余力的同学,可以详细的输出推导的过程,即详细列出每一步使用的产生式。 (四)程序思路 0.定义部分:定义常量、变量、数据结构。 1.初始化:从文件将输入符号串输入到字符缓冲区中。 2.利用递归下降分析法分析,对每个非终结符编写函数,在主函数中调用文法开始符号的函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值