Richard技术博客

每个人穿的衣服是星星的光泽,每条街道是彩虹的纹路,每座房屋是白云的样子,每辆汽车是花朵的颜色。
 
 

与我联系

  • 发短消息

搜索

 

常用链接

  • 我的随笔
  • 我的空间
  • 我的短信
  • 我的评论
  • 更多链接
  • 我的参与
  • 我的新闻
  • 最新评论
  • 我的标签

留言簿

  • 给我留言
  • 查看留言

我的标签

  • python(8)
  • tools(5)
  • C#(5)
  • C# Winform(1)
  • job(1)
  • 工具的使用(1)
  • ADO.NET(1)
  • erp(1)
  • 系统分析与设计(1)

随笔档案

  • 2008年8月 (19)
  • 2008年7月 (6)

最新评论

  • 1. re: 使用Power Designer进行一个完整的系统分析和设计
  • 可有可无吧?
  • --SQL222
  • 2. re: 想跳巢,西安的朋友给个建议
  • 晕,是个菜鸟呀,还这么多要求。
  • --是我啊
  • 3. re: 想跳巢,西安的朋友给个建议
  • 我也在酝酿跳槽,做了3年的对日外包。
    想去西安发展,有合适的麻烦大家给介绍下哈。
  • --呵呵哈哈111
  • 4. re: 想跳巢,西安的朋友给个建议
  • 多谢大家给的意见,真的很感谢大家。6楼的XY.ADDME.CN,我怎么给你投简历啊,我找不到你的邮箱啊。8楼的兄的好强啊,一步步走下来确实很不容易的。10楼的你好,可惜我现在已经不在第一家公司了,6月...
  • --Richard_5758647
  • 5. re: 想跳巢,西安的朋友给个建议
  • 楼主,这段时间工作确实不好找,劝你等到明年春天再跳蚤
  • --北京奥运

阅读排行榜

  • 1. 想跳巢,西安的朋友给个建议(472)
  • 2. 使用DataGridView的ComboBox列,并为CoboBox绑定默认值(192)
  • 3. 使用Power Designer进行一个完整的系统分析和设计(167)
  • 4. 使用vs2005自带的类设计器(159)
  • 5. 使用DataGridView的ComboBox列,并为CoboBox绑定默认值2(154)

评论排行榜

  • 1. 想跳巢,西安的朋友给个建议(14)
  • 2. 使用DataGridView的ComboBox列,并为CoboBox绑定默认值(1)
  • 3. 使用Power Designer进行一个完整的系统分析和设计(1)
  • 4. sql应用(0)
  • 5. 使用vs2005自带的类设计器(0)

60天内阅读排行

  • 1. 想跳巢,西安的朋友给个建议(472)
  • 2. 使用DataGridView的ComboBox列,并为CoboBox绑定默认值(192)
  • 3. 使用Power Designer进行一个完整的系统分析和设计(167)
  • 4. 使用vs2005自带的类设计器(159)
  • 5. 使用DataGridView的ComboBox列,并为CoboBox绑定默认值2(154)

Powered by: 博客园
模板提供:沪江博客
博客园 | 首页 | 发新随笔 | 发新文章 | 联系 | 订阅订阅 | 管理

2008年8月25日

使用Power Designer进行一个完整的系统分析和设计

Power Designer是Sybase公司的CASE 工具集,使用它可以方便地对管理信息系统进行

分析设计,它几乎包括了数据库模型设计的全过程。利用Power Designer可以制作业务流

程图、面向对象模型、概念数据模型、物理数据模型,可以生成VB、JAVA、PB、C#等多

种客户端开发工具的应用程序,还能为数据仓库制作结构模型,并且能对团队设计模型进

行控制。本文通过一个书店信息管理系统讨论利用Power Designer进行数据库设计与实现

的全过程。

电脑应用技术 二零零六总第六十六期

2

1 基于需求的UML 对象设计

UML 是一种标准的图形化建模语言,是面向对象分析设计的一种标准表示方法,并

为不同领域的人们提供统一的交流标准,使得系统设计能够独立于特定的建模语言与开发

过程。UML模拟对象的结构和行为,定义了用例图、类图、序列图、对象图、状态图、协

作图、活动图、组件图和部署图9种图形,用于面向对象的系统建模。在Power Desinger9.5

版本中已经提供对所有9种图的支持。使用UML面向对象模型可以清楚地反映应用程序的

结构(包括动态的和静态的),使我们可以更好地开发和维护整个系统。

系统需求描述:顾客通过网上查询得到自己想要的书目,如果存在,则通过Email发

出购书请求,图书管理员受到请求后向售书系统发送相关信息。系统首先更新库存,然后

向顾客发出邮件进行确认,最后执行“卖出”操作,更新相关数据。

由以上需求可以得到相关的用例图和序列图(如图1、图2所示)。

图1 系统用例图

图2 系统序列图

图3 系统的类图

2 POM 与CDM 之间的转换

在熟悉系统的工作流程后,开始设计与系统相关的类图(如图4所示)。这里主要设计

了四个类,其中ShowBOOK类用来完成用户接口的功能,它的主要任务是使用户能够通过

界面与数据库交互,界面返回查询结果;DbBOOK类主要完成后台数据的处理;DbManager

电脑应用技术 二零零六总第六十六期

3

类用来加载数据库驱动,通过ODBC连接数据库,执行查询条件并对JDBC使用时的错误进

行处理,它被ShowBOOK类和DbBOOK类调用。BOOK类用来记录图书的相关信息:包括

作者,出版日期,售价,售出日期等。

图4 系统的概念数据模

 

图5 系统的物理数据模型

接下来由类图转化得到相应的CDM(如图5所示)。当然,在实际的设计过程中,我们

也可以先得到CDM,然后转换为对应的OOM,再对OOM进行处理(如添加构造函数和成

员函数等)并生成应用程序框架。概念数据模型把现实世界中的信息抽象成实体和联系从

而产生实体关系图(E-R图),它反映了信息系统的整体结构,主要描述不同信息之间的概

念关系,它独立于具体的DBMS,可以让设计人员专注于数据库的设计工作,而不考虑与

具体实施环境相关的问题。OOM与CDM的转换,主要包括类和实体的转换,类属性和实

电脑应用技术 二零零六总第六十六期

4

体属性的转换,继承和关联之间的转换。

3 CDM 与PDM 之间的转换

PDM并不一定要从CDM生成,它可以从数据库脚本产生,可以从数据库中直接逆向

工程产生,也可以直接在Power Designer中完成。

物理数据模型的作用是把概念数据模型与特定的DBMS结合在一起,完成物理数据结

构的生成。同一个CDM可以产生基于不同DBMS的PDM。PDM中包含了DBMS的特征,包

括主键、外键、候选键、视图、索引、触发器、存储过程等等。在Power Designer中每一

种它所支持的RDBMS都有一个DEF文件,每个DEF文件包含了用来生成特定RDBMS数据

库脚本的参数,可以在Power Designer中修改,也可以用文本编辑器修改(文件本身是ASCII

格式),使用这种方法可以使数据类型转换和数据库生成脚本的语法发生全局性的改变,

一般情况下应该谨慎使用。

将CDM转换为PDM的过程中,主要涉及到三类转换:CDM中实体及属性转换为PDM

中的表及表列;CDM中的联系转换为PDM中的参照完整性;CDM中、继承及递归关系的转

换。

本系统使用的是ORACLE数据库系统,转换后的PDM如图6所示。

图6 OOM,CDM和PDM之间的关系

4 生成ORACLE 数据库

生成物理数据模型后,需要对其进行一定的调整才能生成数据到数据库。根据CDM中

的业务规则,我门要做的工作有:保证数据的完整性和一致性,生成视图和索引,编写相

关的触发器和存储过程等等。在生成数据库时,可以有两种方法:一是先生成数据库脚本,

然后在数据库管理系统中执行该脚本以生成数据;另外一种是通过ODBC连接直接在数据

ODBC

OOM

CDM PDM

System request

Application structure

Application source

(java, PB, VB, C#)

Data structures

Business rules

Data integrality

View and index

Trigger and procedure

SQL script DBMS

电脑应用技术 二零零六总第六十六期

5

库中生成数据并产生脚本。ODBC是Windows环境下连接到数据库管理系统的标准接口,

其本质是一个开放的、方便的、标准的应用程序接口。这个API提供了访问关系型和非关

系型DBMS的接口,同时也提供了逆向工程这些DBMS的能力。由于在之前的PDM中已经

选择了ORACLE的DBMS,所以若要生成ORACLE数据库,需要预先建立ORACLE的ODBC

连接。

一般而言,在实际工作中,多采用第一种方法,即先生成SQL脚本,然后人工检查,

确认无误后再生成数据库。

5 OOM、CDM、PDM 之间的关系

OOM, CDM和PDM这三种模型之间是可以相互转化的,它们之间的关系如图7所示。

我们可以根据需要从OOM开始设计,也可以从CDM或从PDM开始设计。

Power Designer根据三种模型对象之间的对应关系和一定的转换规则,实现三种模型

之间的转换。表1给出了它们之间的对应关系。

表1 OOM,CDM和PDM对象之间的转换关系

OOM objects CDM objects PDM objects

Class Entity Table

Class attribute Entity attribute Column

Identifier Primary identifier Primary/foreign key

Identifier Secondary identifier Alternative key

Association Relationship/association Reference/table

Generalization Inheritance Reference

Domain Domain Domain

Association class Association with attributes Table

Class operations N/A Procedure and trigger

Interface/dependency/realization N/A N/A

6 小 结

利用Power Designer进行项目开发,可以有效提高我们的开发速度,尤其是针对大中

型信息管理系统,Power Designer拥有的完整的所有模型类型的元数据知识库将为所有建

模者提供理想的团队开发环境。而其强大的报告生成功能,将使开发人员和用户更迅速地

了解项目的技术细节,可以在很大程度上降低维护费用。当然,Power Designer毕竟只是

一种工具,不可能代替开发人员完成所有的事情,只有当开发人员深刻理解UML,数据库

原理,SQL, JAVA等基础理论和技术时,才能够让Power Designer发挥其最大优势。

参考文献

[1] 刘润东.UML对象设计与编程[M]. 北京:北京希望电子出版社,2001.

[2] 白尚旺. PowerDesigner数据库建模技术[M]. 西安:西安电子科技大学出版社,2002.

[3] Sybase Corporation. Sybase PowerDesigner Tutorial[R]. 2001.

如果使用UML进行一个完整的系统分析和设计,他的步骤是:用例图->序列图->类图->TDD方法的敏捷开发。

那么,对于我们常用的PD,进行一个完整的系统分析和设计应遵循什么步骤呢?先用OOM(对应UML)实现用例图序列图类图->根据类图抽象出CDM(对应ER)->具体出PDM->生成数据库。

当然,最主要的不是流程怎样,而是根据具体的项目要灵活运用。

下面是我辛苦找来的一片文章,希望能给大家带来一点参考。

posted @ 2008-08-25 11:33 Richard_5758647 阅读(167) | 评论 (1) | 编辑
 

2008年8月21日

C#中的委托和事件
CLR & .Net Framework
Part.1 - C# 中的委托和事件
张子阳
jimmyzhang.cnblogs.com
jimmy_dev@163.com

重点:
P5委托的定义
P10事件的由来
P15范例实现的Observer设计模式
P16.Net Framework中标准的委托与事件

引言
委 托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易。它们就像是一道槛儿,过了这个槛的人,觉得真 是太容易了,而没有过去的人每次见到委托和事件就觉得心里别(biè)得慌,混身不自在。本文中,我将通过两个范例由浅入深地讲述什么是委托、为什么要使 用委托、事件的由来、.Net Framework中的委托和事件、委托和事件对Observer设计模式的意义,对它们的中间代码也做了讨论。


将方法作为方法的参数
我们先不管这个标题如何的绕口,也不管委托究竟是个什么东西,来看下面这两个最简单的方法,它们不过是在屏幕上输出一句问候的话语:
public void GreetPeople(string name) { // 做某些额外的事情,比如初始化之类,此处略 EnglishGreeting(name); } public void EnglishGreeting(string name) { Console.WriteLine("Morning, " + name); }
暂且不管这两个方法有没有什么实际意 义。GreetPeople用于向某人问好,当我们传递代表某人姓名的name参数,比如说“Jimmy”,进去的时候,在这个方法中,将调用 EnglishGreeting方法,再次传递name参数,EnglishGreeting则用于向屏幕输出 “Morning, Jimmy”。
现在假设这个程序需要进行全球化,哎呀,不好了,我是中国人,我不明白“Morning”是什么意思,怎么办呢?好吧,我们再加个中文版的问候方法:
public void ChineseGreeting(string name){ Console.WriteLine("早上好, " + name); }
这时候,GreetPeople也需要改一改了,不然如何判断到底用哪个版本的Greeting问候方法合适呢?在进行这个之前,我们最好再定义一个枚举作为判断的依据:
public enum Language{ English, Chinese } public void GreetPeople(string name, Language lang){
//做某些额外的事情,比如初始化之类,此处略 swith(lang){ case Language.English:
EnglishGreeting(name); break; case Language.Chinese: ChineseGreeting(name); break; } }
OK,尽管这样解决了问题,但我不说大家也很容易想到,这个解决方案的可扩展性很差,如果日后我们需要再添加韩文版、日文版,就不得不反复修改枚举和GreetPeople()方法,以适应新的需求。
在考虑新的解决方案之前,我们先看看 GreetPeople的方法签名:
public void GreetPeople(string name, Language lang)
我 们仅看 string name,在这里,string 是参数类型,name 是参数变量,当我们赋给name字符串“jimmy”时,它就代表“jimmy”这个值;当我们赋给它“张子阳”时,它又代表着“张子阳”这个值。然后, 我们可以在方法体内对这个name进行其他操作。哎,这简直是废话么,刚学程序就知道了。
如果你再仔细想想,假如 GreetPeople()方法可以接受一个参数变量,这个变量可以代表另一个方法,当我们给这个变量赋值 EnglishGreeting的时候,它代表着 EnglsihGreeting() 这个方法;当我们给它赋值ChineseGreeting 的时候,它又代表着ChineseGreeting()方法。我们将这个参数变量命名为 MakeGreeting,那么不是可以如同给name赋值时一样,在调用 GreetPeople()方法的时候,给这个MakeGreeting 参数也赋上值么(ChineseGreeting或者EnglsihGreeting等)?然后,我们在方法体内,也可以像使用别的参数一样使用 MakeGreeting。但是,由于MakeGreeting代表着一个方法,它的使用方式应该和它被赋的方法(比如ChineseGreeting) 是一样的,比如:
MakeGreeting(name);
好了,有了思路了,我们现在就来改改GreetPeople()方法,那么它应该是这个样子了:
public void GreetPeople(string name, *** MakeGreeting){
MakeGreeting(name);
}
注意到 *** ,这个位置通常放置的应该是参数的类型,但到目前为止,我们仅仅是想到应该有个可以代表方法的参数,并按这个思路去改写GreetPeople方法,现在就出现了一个大问题:这个代表着方法的MakeGreeting参数应该是什么类型的?
NOTE:这里已不再需要枚举了,因为在给MakeGreeting赋值的时候动态地决定使用哪个方法,是ChineseGreeting还是 EnglishGreeting,而在这个两个方法内部,已经对使用“morning”还是“早上好”作了区分。
聪明的你应该已经想到了,现在是委托该出场的时候了,但讲述委托之前,我们再看看MakeGreeting参数所能代表的 ChineseGreeting()和EnglishGreeting()方法的签名:
public void EnglishGreeting(string name) public void ChineseGreeting(string name)
如 同name可以接受String类型的“true”和“1”,但不能接受bool类型的true和int类型的1一样。MakeGreeting的 参数类型定义 应该能够确定 MakeGreeting可以代表的 方法种类,再进一步讲,就是MakeGreeting可以代表的方法 的 参数类型和返回类型。
于是,委托出现了:它定义了MakeGreeting参数所能代表的方法的种类,也就是MakeGreeting参数的类型。
NOTE:如果上面这句话比较绕口,我把它翻译成这样:string 定义了name参数所能代表的值的种类,也就是name参数的类型。
本例中委托的定义:
public delegate void GreetingDelegate(string name);
可以与上面EnglishGreeting()方法的签名对比一下,除了加入了delegate关键字以外,其余的是不是完全一样?
现在,让我们再次改动GreetPeople()方法,如下所示:
public void GreetPeople(string name, GreetingDelegate MakeGreeting){
MakeGreeting(name);
}
如 你所见,委托GreetingDelegate出现的位置与 string相同,string是一个类型,那么GreetingDelegate应该也是一个类型,或者叫类(Class)。但是委托的声明方式和类却 完全不同,这是怎么一回事?实际上,委托在编译的时候确实会编译成类。因为Delegate是一个类,所以在任何可以声明类的地方都可以声明委托。更多的 内容将在下面讲述,现在,请看看这个范例的完整代码:
using System; using System.Collections.Generic; using System.Text; namespace Delegate { //定义委托,它定义了可以代表的方法的类型 public delegate void GreetingDelegate(string name);
class Program {
private static void EnglishGreeting(string name) { Console.WriteLine("Morning, " + name); } private static void ChineseGreeting(string name) { Console.WriteLine("早上好, " + name); } //注意此方法,它接受一个GreetingDelegate类型的方法作为参数 private static void GreetPeople(string name, GreetingDelegate MakeGreeting) { MakeGreeting(name); } static void Main(string[] args) { GreetPeople("Jimmy Zhang", EnglishGreeting); GreetPeople("张子阳", ChineseGreeting); Console.ReadKey(); } } }
输出如下: Morning, Jimmy Zhang 早上好, 张子阳
我们现在对委托做一个总结:
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。


将方法绑定到委托
看到这里,是不是有那么点如梦初醒的感觉?于是,你是不是在想:在上面的例子中,我不一定要直接在GreetPeople()方法中给 name参数赋值,我可以像这样使用变量:
static void Main(string[] args) { string name1, name2; name1 = "Jimmy Zhang"; name2 = "张子阳"; GreetPeople(name1, EnglishGreeting); GreetPeople(name2, ChineseGreeting);
Console.ReadKey(); }
而既然委托GreetingDelegate 和 类型 string 的地位一样,都是定义了一种参数类型,那么,我是不是也可以这么使用委托?
static void Main(string[] args) { GreetingDelegate delegate1, delegate2; delegate1 = EnglishGreeting; delegate2 = ChineseGreeting; GreetPeople("Jimmy Zhang", delegate1); GreetPeople("张子阳", delegate2); Console.ReadKey(); }
如你所料,这样是没有问题的,程序一如预料的那样输出。这里,我想说的是委托不同于string的一个特性:可以将多个方法赋给同一个委托,或者叫将多个方法绑定到同一个委托,当调用这个委托的时候,将依次调用其所绑定的方法。在这个例子中,语法如下:
static void Main(string[] args) { GreetingDelegate delegate1; delegate1 = EnglishGreeting; // 先给委托类型的变量赋值 delegate1 += ChineseGreeting; // 给此委托变量再绑定一个方法 // 将先后调用 EnglishGreeting 与 ChineseGreeting 方法 GreetPeople("Jimmy Zhang", delegate1); Console.ReadKey();
}
输出为: Morning, Jimmy Zhang 早上好, Jimmy Zhang
实际上,我们可以也可以绕过GreetPeople方法,通过委托来直接调用EnglishGreeting和ChineseGreeting:
static void Main(string[] args) { GreetingDelegate delegate1; delegate1 = EnglishGreeting; // 先给委托类型的变量赋值 delegate1 += ChineseGreeting; // 给此委托变量再绑定一个方法 // 将先后调用 EnglishGreeting 与 ChineseGreeting 方法 delegate1 ("Jimmy Zhang"); Console.ReadKey();
}
NOTE:这在本例中是没有问题的,但回头看下上面GreetPeople()的定义,在它之中可以做一些对于EnglshihGreeting和ChineseGreeting来说都需要进行的工作,为了简便我做了省略。
注意这里,第一次用的“=”,是赋值的语法;第二次,用的是“+=”,是绑定的语法。如果第一次就使用“+=”,将出现“使用了未赋值的局部变量”的编译错误。
我们也可以使用下面的代码来这样简化这一过程:
GreetingDelegate delegate1 = new GreetingDelegate(EnglishGreeting);
delegate1 += ChineseGreeting; // 给此委托变量再绑定一个方法
看到这里,应该注意到,这段代码第一条语句与实例化一个类是何其的相似,你不禁想到:上面第一次绑定委托时不可以使用“+=”的编译错误,或许可以用这样的方法来避免:
GreetingDelegate delegate1 = new GreetingDelegate();
delegate1 += EnglishGreeting; // 这次用的是 “+=”,绑定语法。
delegate1 += ChineseGreeting; // 给此委托变量再绑定一个方法
但 实际上,这样会出现编译错误: “GreetingDelegate”方法没有采用“0”个参数的重载。尽管这样的结果让我们觉得有点沮丧,但是编译的提示:“没有0个参数的重载”再次 让我们联想到了类的构造函数。我知道你一定按捺不住想探个究竟,但再此之前,我们需要先把基础知识和应用介绍完。
既然给委托可以绑定一个方法,那么也应该有办法取消对方法的绑定,很容易想到,这个语法是“-=”:
static void Main(string[] args) {
GreetingDelegate delegate1 = new GreetingDelegate(EnglishGreeting);
delegate1 += ChineseGreeting; // 给此委托变量再绑定一个方法
// 将先后调用 EnglishGreeting 与 ChineseGreeting 方法
GreetPeople("Jimmy Zhang", delegate1);
Console.WriteLine();
delegate1 -= EnglishGreeting; //取消对EnglishGreeting方法的绑定
// 将仅调用 ChineseGreeting
GreetPeople("张子阳", delegate1);
Console.ReadKey();
}
输出为:
Morning, Jimmy Zhang
早上好, Jimmy Zhang
早上好, 张子阳
让我们再次对委托作个总结:
使用委托可以将多个方法绑定到同一个委托变量,当调用此变量时(这里用“调用”这个词,是因为此变量代表一个方法),可以依次调用所有绑定的方法。


事件的由来
我 们继续思考上面的程序:上面的三个方法都定义在Programe类中,这样做是为了理解的方便,实际应用中,通常都是 GreetPeople 在一个类中,ChineseGreeting和 EnglishGreeting 在另外的类中。现在你已经对委托有了初步了解,是时候对上面的例子做个改进了。假设我们将GreetingPeople()放在一个叫 GreetingManager的类中,那么新程序应该是这个样子的:
namespace Delegate {
//定义委托,它定义了可以代表的方法的类型
public delegate void GreetingDelegate(string name);
//新建的GreetingManager类
public class GreetingManager{
public void GreetPeople(string name, GreetingDelegate MakeGreeting) {
MakeGreeting(name);
}
}
class Program {
private static void EnglishGreeting(string name) {
Console.WriteLine("Morning, " + name);
}
private static void ChineseGreeting(string name) {
Console.WriteLine("早上好, " + name);
}
static void Main(string[] args) {
// ... ...
}
}
}
这个时候,如果要实现前面演示的输出效果,Main方法我想应该是这样的:
static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
gm.GreetPeople("Jimmy Zhang", EnglishGreeting);
gm.GreetPeople("张子阳", ChineseGreeting);
}
我们运行这段代码,嗯,没有任何问题。程序一如预料地那样输出了:
Morning, Jimmy Zhang
早上好, 张子阳
现在,假设我们需要使用上一节学到的知识,将多个方法绑定到同一个委托变量,该如何做呢?让我们再次改写代码:
static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
GreetingDelegate delegate1;
delegate1 = EnglishGreeting;
delegate1 += ChineseGreeting;
gm.GreetPeople("Jimmy Zhang", delegate1);
}
输出:
Morning, Jimmy Zhang
早上好, Jimmy Zhang
到 了这里,我们不禁想到:面向对象设计,讲究的是对象的封装,既然可以声明委托类型的变量(在上例中是delegate1),我们何不将这个变量封装到 GreetManager类中?在这个类的客户端中使用不是更方便么?于是,我们改写GreetManager类,像这样:
public class GreetingManager{
//在GreetingManager类的内部声明delegate1变量
public GreetingDelegate delegate1;
public void GreetPeople(string name, GreetingDelegate MakeGreeting) {
MakeGreeting(name);
}
}
现在,我们可以这样使用这个委托变量:
static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
gm.delegate1 = EnglishGreeting;
gm.delegate1 += ChineseGreeting;
gm.GreetPeople("Jimmy Zhang", gm.delegate1);
}
尽管这样达到了我们要的效果,但是这里存在着问题:
在这里,delegate1和我们平时用的string类型的变量没有什么分别,而我们知道,并不是所有的字段都应该声明成public,合适的做法是应该public的时候public,应该private的时候private。
我们先看看如果把 delegate1 声明为 private会怎样?结果就是:这简直就是在搞笑。因为声明委托的目的就是为了把它暴露在类的客户端进行方法的注册,你把它声明为private了,客户端对它根本就不可见,那它还有什么用?
再看看把delegate1 声明为 public 会怎样?结果就是:在客户端可以对它进行随意的赋值等操作,严重破坏对象的封装性。
最后,第一个方法注册用“=”,是赋值语法,因为要进行实例化,第二个方法注册则用的是“+=”。但是,不管是赋值还是注册,都是将方法绑定到委托上,除了调用时先后顺序不同,再没有任何的分别,这样不是让人觉得很别扭么?
现在我们想想,如果delegate1不是一个委托类型,而是一个string类型,你会怎么做?答案是使用属性对字段进行封装。
于是,Event出场了,它封装了委托类型的变量,使得:在类的内部,不管你声明它是public还是protected,它总是private的。在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同。
我们改写GreetingManager类,它变成了这个样子:
public class GreetingManager{
//这一次我们在这里声明一个事件
public event GreetingDelegate MakeGreet;
public void GreetPeople(string name, GreetingDelegate MakeGreeting) {
MakeGreeting(name);
}
}
很容易注意到:MakeGreet 事件的声明与之前委托变量delegate1的声明唯一的区别是多了一个event关键字。看到这里,在结合上面的讲解,你应该明白到:事件其实没什么不好理解的,声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已。
为了证明上面的推论,如果我们像下面这样改写Main方法:
static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
gm.MakeGreet = EnglishGreeting; // 编译错误1
gm.MakeGreet += ChineseGreeting;
gm.GreetPeople("Jimmy Zhang", gm.MakeGreet); //编译错误2
}
会得到编译错误:事件“Delegate.GreetingManager.MakeGreet”只能出现在 += 或 -= 的左边(从类型“Delegate.GreetingManager”中使用时除外)。


事件和委托的编译代码

这时候,我们注释掉编译错误的行,然后重新进行编译,再借助Reflactor来对 event的声明语句做一探究,看看为什么会发生这样的错误:
public event GreetingDelegate MakeGreet;
可 以看到,实际上尽管我们在GreetingManager里将 MakeGreet 声明为public,但是,实际上MakeGreet会被编译成 私有字段,难怪会发生上面的编译错误了,因为它根本就不允许在GreetingManager类的外面以赋值的方式访问,从而验证了我们上面所做的推论。
我们再进一步看下MakeGreet所产生的代码:
private GreetingDelegate MakeGreet; //对事件的声明 实际是 声明一个私有的委托变量
[MethodImpl(MethodImplOptions.Synchronized)]
public void add_MakeGreet(GreetingDelegate value){
this.MakeGreet = (GreetingDelegate) Delegate.Combine(this.MakeGreet, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void remove_MakeGreet(GreetingDelegate value){
this.MakeGreet = (GreetingDelegate) Delegate.Remove(this.MakeGreet, value);
}
现 在已经很明确了:MakeGreet事件确实是一个GreetingDelegate类型的委托,只不过不管是不是声明为public,它总是被声明为 private。另外,它还有两个方法,分别是add_MakeGreet和remove_MakeGreet,这两个方法分别用于注册委托类型的方法和 取消注册。实际上也就是: “+= ”对应 add_MakeGreet,“-=”对应remove_MakeGreet。而这两个方法的访问限制取决于声明事件时的访问限制符。
在add_MakeGreet()方法内部,实际上调用了System.Delegate的Combine()静态方法,这个方法用于将当前的变量添加到委托链表中。我们前面提到过两次,说委托实际上是一个类,在我们定义委托的时候:
public delegate void GreetingDelegate(string name);
当编译器遇到这段代码的时候,会生成下面这样一个完整的类:
public class GreetingDelegate:System.MulticastDelegate{
public GreetingDelegate(object @object, IntPtr method);
public virtual IAsyncResult BeginInvoke(string name, AsyncCallback callback, object @object);
public virtual void EndInvoke(IAsyncResult result);
public virtual void Invoke(string name);
}
关于这个类的更深入内容,可以参阅《CLR Via C#》等相关书籍,这里就不再讨论了。


委托、事件与Observer设计模式

范例说明
上面的例子已不足以再进行下面的讲解了,我们来看一个新的范例,因为之前已经介绍了很多的内容,所以本节的进度会稍微快一些:
假设我们有个高档的热水器,我们给它通上电,当水温超过95度的时候:1、扬声器会开始发出语音,告诉你水的温度;2、液晶屏也会改变水温的显示,来提示水已经快烧开了。
现 在我们需要写个程序来模拟这个烧水的过程,我们将定义一个类来代表热水器,我们管它叫:Heater,它有代表水温的字段,叫做temperature; 当然,还有必不可少的给水加热方法BoilWater(),一个发出语音警报的方法MakeAlert(),一个显示水温的方法,ShowMsg()。
namespace Delegate {
class Heater {
private int temperature; // 水温
// 烧水
public void BoilWater() {
for (int i = 0; i <= 100; i++) {
temperature = i;
if (temperature > 95) {
MakeAlert(temperature);
ShowMsg(temperature);
}
}
}
// 发出语音警报
private void MakeAlert(int param) {
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:" , param);
}
// 显示水温
private void ShowMsg(int param) {
Console.WriteLine("Display:水快开了,当前温度:{0}度。" , param);
}
}
class Program {
static void Main() {
Heater ht = new Heater();
ht.BoilWater();
}
}
}
Observer设计模式简介
上面的例子显然能完成我们之前描述的工作,但是却并不够好。现在假设热水器由三部分组成:热水器、警报器、显示器,它们来自于不同厂商并进行了组装。那么,应该是热水器仅仅负责烧水,它不能发出警报也不能显示水温;在水烧开时由警报器发出警报、显示器显示提示和水温。
这时候,上面的例子就应该变成这个样子:
// 热水器
public class Heater {
private int temperature;
// 烧水
private void BoilWater() {
for (int i = 0; i <= 100; i++) {
temperature = i;
}
}
}
// 警报器
public class Alarm{
private void MakeAlert(int param) {
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:" , param);
}
}
// 显示器
public class Display{
private void ShowMsg(int param) {
Console.WriteLine("Display:水已烧开,当前温度:{0}度。" , param);
}
}
这里就出现了一个问题:如何在水烧开的时候通知报警器和显示器?在继续进行之前,我们先了解一下Observer设计模式,Observer设计模式中主要包括如下两类对象:
.. Subject:监视对象,它往往包含着其他对象所感兴趣的内容。在本范例中,热水器就是一个监视对象,它包含的其他对象所感兴趣的内容,就是temprature字段,当这个字段的值快到100时,会不断把数据发给监视它的对象。
.. Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer有警报器和显示器,它们采取的行动分别是发出警报和显示水温。
在本例中,事情发生的顺序应该是这样的:
1. 警报器和显示器告诉热水器,它对它的温度比较感兴趣(注册)。
2. 热水器知道后保留对警报器和显示器的引用。
3. 热水器进行烧水这一动作,当水温超过95度时,通过对警报器和显示器的引用,自动调用警报器的MakeAlert()方法、显示器的ShowMsg()方法。
类似这样的例子是很多的,GOF对它进行了抽象,称为Observer设计模式:Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖
于它的对象会被自动告知并更新。Observer模式是一种松耦合的设计模式。
实现范例的Observer设计模式
我们之前已经对委托和事件介绍很多了,现在写代码应该很容易了,现在在这里直接给出代码,并在注释中加以说明。
using System;
using System.Collections.Generic;
using System.Text;
namespace Delegate {
// 热水器
public class Heater {
private int temperature;
public delegate void BoilHandler(int param); //声明委托
public event BoilHandler BoilEvent; //声明事件
// 烧水
public void BoilWater() {
for (int i = 0; i <= 100; i++) {
temperature = i;
if (temperature > 95) {
if (BoilEvent != null) { //如果有对象注册
BoilEvent(temperature); //调用所有注册对象的方法
}
}
}
}
}
// 警报器
public class Alarm {
public void MakeAlert(int param) {
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:", param);
}
}
// 显示器
public class Display {
public static void ShowMsg(int param) { //静态方法
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", param);
}
}
class Program {
static void Main() {
Heater heater = new Heater();
Alarm alarm = new Alarm();
heater.BoilEvent += alarm.MakeAlert; //注册方法
heater.BoilEvent += (new Alarm()).MakeAlert; //给匿名对象注册方法
heater.BoilEvent += Display.ShowMsg; //注册静态方法
heater.BoilWater(); //烧水,会自动调用注册过对象的方法
}
}
}
输出为:
Alarm:嘀嘀嘀,水已经 96 度了:
Alarm:嘀嘀嘀,水已经 96 度了:
Display:水快烧开了,当前温度:96度。
// 省略...


.Net Framework中的委托与事件

尽管上面的范例很好地完成了我们想要完成的工作,但是我们不仅疑惑:为什么.Net Framework 中的事件模型和上面的不同?为什么有很多的EventArgs参数?
在回答上面的问题之前,我们先搞懂 .Net Framework的编码规范:
.. 委托类型的名称都应该以EventHandler结束。
.. 委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)。
.. 事件的命名为 委托去掉 EventHandler之后剩余的部分。
.. 继承自EventArgs的类型应该以EventArgs结尾。
再做一下说明:
1. 委托声明原型中的Object类型的参数代表了Subject,也就是监视对象,在本例中是 Heater(热水器)。回调函数(比如Alarm的MakeAlert)可以通过它访问触发事件的对象(Heater)。
2. EventArgs 对象包含了Observer所感兴趣的数据,在本例中是temperature。
上 面这些其实不仅仅是为了编码规范而已,这样也使得程序有更大的灵活性。比如说,如果我们不光想获得热水器的温度,还想在Observer端(警报器或者显 示器)方法中获得它的生产日期、型号、价格,那么委托和方法的声明都会变得很麻烦,而如果我们将热水器的引用传给警报器的方法,就可以在方法中直接访问热 水器了。
现在我们改写之前的范例,让它符合 .Net Framework 的规范:
using System;
using System.Collections.Generic;
using System.Text;
namespace Delegate {
// 热水器
public class Heater {
private int temperature;
public string type = "RealFire 001"; // 添加型号作为演示
public string area = "China Xian"; // 添加产地作为演示
//声明委托
public delegate void BoiledEventHandler(Object sender, BoliedEventArgs e);
public event BoiledEventHandler Boiled; //声明事件
// 定义BoliedEventArgs类,传递给Observer所感兴趣的信息
public class BoliedEventArgs : EventArgs {
public readonly int temperature;
public BoliedEventArgs(int temperature) {
this.temperature = temperature;
}
}
// 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视
protected virtual void OnBolied(BoliedEventArgs e) {
if (Boiled != null) { // 如果有对象注册
Boiled(this, e); // 调用所有注册对象的方法
}
}
// 烧水。
public void BoilWater() {
for (int i = 0; i <= 100; i++) {
temperature = i;
if (temperature > 95) {
//建立BoliedEventArgs 对象。
BoliedEventArgs e = new BoliedEventArgs(temperature);
OnBolied(e); // 调用 OnBolied方法
}
}
}
}
// 警报器
public class Alarm {
public void MakeAlert(Object sender, Heater.BoliedEventArgs e) {
Heater heater = (Heater)sender; //这里是不是很熟悉呢?
//访问 sender 中的公共字段
Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type);
Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature);
Console.WriteLine();
}
}
// 显示器
public class Display {
public static void ShowMsg(Object sender, Heater.BoliedEventArgs e) { //静态方法
Heater heater = (Heater)sender;
Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type);
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
Console.WriteLine();
}
}
class Program {
static void Main() {
Heater heater = new Heater();
Alarm alarm = new Alarm();
heater.Boiled += alarm.MakeAlert; //注册方法
heater.Boiled += (new Alarm()).MakeAlert; //给匿名对象注册方法
heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert); //也可以这么注册
heater.Boiled += Display.ShowMsg; //注册静态方法
heater.BoilWater(); //烧水,会自动调用注册过对象的方法
}
}
}
输出为:
Alarm:China Xian - RealFire 001:
Alarm: 嘀嘀嘀,水已经 96 度了:
Alarm:China Xian - RealFire 001:
Alarm: 嘀嘀嘀,水已经 96 度了:
Alarm:China Xian - RealFire 001:
Alarm: 嘀嘀嘀,水已经 96 度了:
Display:China Xian - RealFire 001:
Display:水快烧开了,当前温度:96度。
// 省略 ...
总结
在本文中我首先通过一个GreetingPeople的小程序向大家介绍了委托的概念、委托用来做什么,随后又引出了事件,接着对委托与事件所产生的中间代码做了粗略的讲述。
在第二个稍微复杂点的热水器的范例中,我向大家简要介绍了 Observer设计模式,并通过实现这个范例完成了该模式,随后讲述了.Net Framework中委托、事件的实现方式。
本文的源码可以在http://www.tracefact.net/sourcecode/delegates-and-events.rar 下载。
希望这篇文章能给你带来帮助。
posted @ 2008-08-21 15:22 Richard_5758647 阅读(4) | 评论 (0) | 编辑
 
Google Code Host的使用说明

Google Code Host的使用说明

by shootsoft

yinjun@shootsoft.net

http://www.shootsoft.net


1. Eclipse的Subversion使用说明

开发工具以Eclipse为主,所以Eclipse首先需要安装一个Subversion的插件。参考下面的网址:

http://www.ibm.com/developerworks/cn/opensource/os-ecl-subversion/


项目组的所有成员必须都要按照以上的操作安装好插件,并且注册Google的Gmail帐户。

2.Google Code Host说明

项目组组长到http://code.google.com/hosting/创建新项目(Create a new project)过程省略。最后会看到项目的协作平台网址:http://code.google.com/p/group6homework/。(group6homework是项目名称)组长创建完成后还需要把组员的帐户添加进来:通过[Administer]—[Project Members]就可以对项目组成员帐户进行管理。


创建完成后组长需要安装http://tortoisesvn.net/downloads Subversion的客户端插件进行项目首次的Check In操作。

操作如下:

到Eclipse的项目的workspace目录下,进入需要协作的项目的目录,比如我的:

D:"shootsoft"GP6Platform

单击鼠标右键,选择[TortoiseSVN]—[Import]然后输入:

https://group6homework.googlecode.com/svn/trunk/

注意:

  • 这里网址如果你不太清楚可以登录

http://code.google.com/p/group6homework/source查看

  • Google Code Host使用的密码是随机生成的,如果已经登录Google,可以查看以下网址获得密码:

http://code.google.com/hosting/settings

首次登录可能需要安装证书和输入密码。完成后TortoiseSVN就会自动把文件夹

D:"shootsoft"workspace"GP6Platform下的所有文件同步到服务器上去了。


3. Google Code Host与Eclipse

Check In操作完成后组长还需要将项目Check Out出来,真正和Eclipse中的项目结合,组员也需要这样做:

1.将自己的项目文件夹备份并且从Eclipse中删除。需要选择第一项,连同文件夹一起删除。

2.按照http://www.ibm.com/developerworks/cn/opensource/os-ecl-subversion/中的说明进行Import操作,操作结果如下所示:

3.这时点击Next按钮,选择第一项,然后点击Finish按钮。


4.通过Windows菜单,[Show View]—[Other]


5.在弹出的新窗口中选择“SVN—SVN资源库”


6.在刚才Import进来的那个资源库上单击鼠标右键,选择“检出为(A)...”


7.然后在新窗口中中输入项目名称

点击“Finish”按钮。


稍微等待一会儿,程序就会全部下载回来了。


8.我的Tomcat5补丁放在了D:"Tomcat5补丁目录下,请各位参考我的未知把补丁放置好。

如果导入的项目有红叉叉,在项目上点击鼠标右键,选择“Close Project”然后再打开就好了。这时可以清楚的看到项目上图标发生了一点点变化:

在上面的第3步上,按道理应该可以作为项目可以直接检出,但是我这里操作总是出错,所以只有按照稍微烦琐一点的步骤来操作了。


4. Subversion的使用

如果你对某一个文件进行了修改,想要把这个文件提交到服务器上去,就需要在需要提交的文件上单击鼠标右键,通过Team菜单来[提交]

如果你需要把修改过的文件使用服务器上的来覆盖,可以通过Team菜单的[更新]来进行。

Subversion的使用非常简单,但是要深入探究也可以说上几千字,还是建议通过官方或者非官方的教程来学习:

http://www.baidu.com/s?tn=searches_dg&ie=utf-8&word=subversion+%E6%95%99%E7%A8%8B

http://www.baidu.com/s?wd=Subversion+Eclipse&cl=3


posted @ 2008-08-21 15:20 Richard_5758647 阅读(7) | 评论 (0) | 编辑
 
ERP概念
怎么用c#调用java web service            2008-7-15 17:09

    java端用axis开发基于soap的webservice,然后在。net中add web reference,方法和添加。net自己的webservice一样,。net会自己生成相应的代理类,其他的我就不用细说了。
    先 用JAVA写好WEB SERVICE,然后会生成一个wsdl的文件地址.首先取得这个地址. 然后打开"Visual Studio.Net  2003 命令提示,在里面输入"wsdl 后面接wsdl的地址",这样会生成一个代理类,生成这个类文件后,其余的就与调用一般的类没有什么区别的了.

    如 果用c#调用java 的 webservice 时,发现调用返回值为基本类型(如 xsd:string xsd:int)的服务能过正常返回,而调用返回复杂类型如自定义对象时却返回 null,同时抓包发现服务器段明明已经正常答复soap消息。 就需要考虑命名空间的问题。
    在我碰到的问题中,由于我把用来返回结果的bean 单独放到一个 xxx.xxx.bean 包中,而把webservice 的文件放在 xxx.xxx.service包中,在用wtp生成 webservice 服务时就把它们放到不同的命名空间中去了。
解决方案:
    把用来的bean文件放置到与service同一个package中,这样用wtp lomboz之类工具生成时就直接会在一个命名空间中。

Java端的webservice中saveUser(JafUser user)方法中的JafUser类代码如下:
java 代码
/**
*
* @author lixy 2006-12-14 10:16:04
*
*/
public class JafUser implements java.io.Serializable {
// Fields
private String userId;
private String userName;
private Integer regionId;
// Constructors
/** default constructor */
public JafUser() {
}
public Integer getRegionId() {
return regionId;
}
public void setRegionId(Integer regionId) {
this.regionId = regionId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String toString() {
StringBuffer sb = new StringBuffer("[ ");
sb.append("userId = "+this.userId).append(",");
sb.append("userName = "+this.userName).append(",");
sb.append("regionId = "+this.regionId).append(" ]");
return sb.toString();
}
}
客户端c# 代码:
ConsoleApplication1.com.lixy.ws.UserServiceEx manager = new ConsoleApplication1.com.lixy.ws.UserServiceEx();
JafUser user = new JafUser();
user.userId = "lixy01";
user.userName = "lixiangyang01";
user.regionId = 4301;
user.regionIdSpecified = true;
String result = manager.saveUser(user);
Console.WriteLine("Result = " + result);
Console.ReadLine();
    regionIdSpecified 虽然不是JafUser对象()中的属性,但是在测试程序时,发现只有将user.regionIdSpecified设为 true,regionId才被发送到webservice端。


ERP系统的C/S与B/S结构
            2008-7-13 16:57

C/S 与B/S的关系与管理需求是紧密联系的,在集团管理中有 集中式管理与分布式管理的区别一样,集中式管理要求对数据实时监控,因为那些外地的分公司需实施进行远程操作数据的读写与传输,所以需要用B/S结构来保 证数据操作实时性的(只要能上网就能登入操作).应用产品、系统产品、网络环境的不同,又将其细分为:C/S结构应用方案;系统更新时客户端均须维护,对 网络带宽要求较高,主要适合局域网运行.B/S结构应用方案b/s:客户端免安装,客户端免维护,方便的查询,所有查询均可保存个性化方案和公用方案 集团管理分布管理就是用C/S结构的来构成个个区域(各分公司)数据存储与操作,而后在定期上报数据给总部汇总,这样操作的数据不需要B/S结构。根据企 业不同的要可选择不同的模式,不是把有的企业都需要B/S,也不是所有的C/S产品能满足所有的企业需求(如作全国分销的信息化系统绝对需要B/S结构的 产品来实时监控个个分销公司和营销网点)子公司的地域和带宽进行判断,一般建议异地的子公司采用B/S,与集团总部在同一局域网内的子公司,并且是高带宽 的子公司采用C/S。


MRP            2008-7-13 17:01

    MRP 是Material Requirement Planning(物料需求)计划的英文缩写。其基本原理是根据物料清单(BOM)把产品生产计划分解成原材料需求计划(包括半成品、外协等),在这个运 算过程中,需要综合考虑生产能力、库存、采购周期、生产周期、最小批量等等各种要素。
    MRP 解决了企业物料供需信息集成,但是还没有说明企业的经营效益。MRP Ⅱ 同MRP 的主要区别就是它运用管理会计的概念,用货币形式说明了执行企业“ 物料计划” 带来的效益,实现物料信息同资金信息集成。衡量企业经营效益首先要计算产品成本,产品成本的实际发生过程,还要以MRP系统的产品结构为基础,从最底层采 购件的材料费开始,逐层向上将每一件物料的材料费、人工费和制造费(间接成本)累积,得出每一层零部件直至最终产品的成本。再进一步结合市场营销,分析各 类产品的获利性。
    MRP Ⅱ 把传统的帐务处理同发生帐务的事务结合起来,不仅说明帐务的资金现状,而且追溯资金的来龙去脉— — 例如将体现债务债权关系的应付帐、应收帐同采购业务和销售业务集成起来、同供应商或客户的业绩或信誉集成起来、同销售和生产计划集成起来等,按照物料位 置、数量或价值变化,定义“ 事务处理(Transaction)”,使与生产相关的财务信息直接由生产活动生成。在定义事务处理相关的会计科目之间,按设定的借贷关系,自动转帐登 录,保证了“ 资金流(财务帐)” 同“ 物流(实物帐)” 的同步和一致,改变了资金信息滞后于物料信息的状况,便于实时做出决策。


MRP/ERP软件            2008-7-13 17:02
    软件方面,国内市场上一些主流的ERP厂商都提供这个功能。如SAP、Oracle、symix、SSA、QAD、CASE等。国内的财务软件供应商虽然也称是ERP软件,但在这方面不具备实用功能,有些则根本没有。
    很少有单独出售MRP的,都是与ERP或MRPII结合起来实施。国内的代表性软件有开思、和佳、利玛、经纬等,另外速达据说也不错,但我没有见过。
    金碟和用友是在玩概念,不是真正的MRP,用友新出的NC还可以,金碟K3不行,只是进销存加财务,没有完成真正的MRP。
     是否具有真正的MRP流程是判别一个ERP软件优劣的重要标准,它是比较完全的企业自动化,可以与日本的JIT(JUST IN TIME)相媲美。
    是人的计划,不是计算机软件!不是每个公司都一样的,学习mrp的概念固然重要,但吸收才是关键!
posted @ 2008-08-21 15:20 Richard_5758647 阅读(5) | 评论 (0) | 编辑
 
版本管理工具的使用
   windows下的客户端推荐使用TortoiseSVN。TortoiseSVN是windows平台下最经典的SVN客户端,操作及其简便直观,直接跟windows系统结合,通过文件/文件夹右键菜单方式进行管理您的项目.不过我喜欢用它的命令行,因为以前用CVS的时候就是用命令行,而SVN的命令行方式几乎和CVS是一样的,所以很快上手了。

    从http://subversion.tigris.org获 取subversion for windows的版本,安装之后就有了svn.exe这个基于命令行的客户端工具。当然服务器端的程序也有了,这里就不关心如何配置SVN服务了。安装程 序把svn.exe的路径加入了path环境变量,我们已经可以在命令行中直接输入svn就可以使用了。

如果你不知道命令怎么用svn命令,可通过如下方式查询:
svn help
知道了子命令,但是不知道子命令的用法,还可以查询:
svn help ci

开发人员常用命令

导入项目
svn import http://svn.chinasvn.com:82/pthread --message "Start project"

导出项目
svn checkout http://svn.chinasvn.com:82/pthread

采用 export 的方式来导出一份“干净”的项目
svn export http://svn.chinasvn.com:82/pthread pthread

为失败的事务清场
svn cleanup

在本地进行代码修改,检查修改状态
svn status -v
svn diff

更新(update)服务器数据到本地
svn update directory
svn update file

增加(add)本地数据到服务器
svn add file.c
svn add dir

对文件进行改名和删除
svn mv b.c bb.c
svn rm d.c

提交(commit)本地文档到服务器
svn commit
svn ci
svn ci -m "commit"

查看日志
svn log directory
svn log file

相关的一些东西:
1、在本地文件中,每个目录下都有一个.svn文件夹(属性为隐藏),保存了相关的信息。
2、注册环境变量SVN_EDITOR为"E:"Program Files"Vim"vim71"gvim.exe",结果在svn ci的时候,出现错误:

'E:"Program' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
svn: 提交失败(细节如下):
svn: system('E:"Program Files"Vim"vim71"gvim.exe svn-commit.tmp') 返回 1

把SVN_EDITOR改为"gvim.exe",并且在path中添加路径"E:"Program Files"Vim"vim71"",这样就可以在提交的时候用vim编写注释了。

附:
提供免费SVN服务的网站:
http://www.svnhost.cn/(推荐)
http://www.chinasvn.com
http://www.javaforge.com
http://unfuddle.com
http://svn.coollittlethings.com/index.php(针对开源免费,针对私人项目收费)
posted @ 2008-08-21 13:06 Richard_5758647 阅读(9) | 评论 (0) | 编辑
 

2008年8月20日

PYTHON SNACK 文件处理
Code

#coding:gbk

import sys

print '中文'

print 'plese input file name'
oldfilename 
= sys.stdin.readline()

print 'input new filename'
newfilename 
= sys.stdin.readline()

oldfile 
= open(oldfilename.replace('\n',''))
newfile 
= open(newfilename.replace('\n',''),'w')

for s in oldfile.xreadlines():
    
if len(s.split('说:')) >1:
        newfile.write(s.split(
'说:')[1])
        
    
else:
        newfile.write(s)        

oldfile.close()
newfile.close()

print 'operate completele'

posted @ 2008-08-20 17:51 Richard_5758647 阅读(5) | 评论 (0) | 编辑
 
DataTable删除行
Code
//方法一
DataRow[]   drs   =   DataTabl1.Select("id=2   or   id=4");  
for(   int   i=0   ;   i<drs.Count   ;   i++   )  
{  
     DataTable1.Rows.Remove(   drs[i]   );  
}
//方法二
dt.Rows[1].Delete();  
dt.Rows[
3].Delete();

 
posted @ 2008-08-20 15:17 Richard_5758647 阅读(6) | 评论 (0) | 编辑
 
Python开发工具
我先给一个初步的表格吧,大家如果有什么意见,或有补充,欢迎提出。有些我没有用过,先不写了。
以下是我使用过的python IDE:

┌─────┬────┬────┬──┬────┬──┬─────┬─────┐
│IDE name  │自动补全│智能感知│调试│语法检查│开源│特别注意  │  推荐度  │
├─────┼────┼────┼──┼────┼──┼─────┼─────┤
│IDLE      │手动    │有(很差)│用库│无      │开源│          │★★      │
├─────┼────┼────┼──┼────┼──┼─────┼─────┤
│PythonWin │手动  │有      │用库│无      │开源│Win Only  │★★★    │
├─────┼────┼────┼──┼────┼──┼─────┼─────┤
│SPE       │无      │有      │WPDB│存盘时  │开源│          │★★★★★│
├─────┼────┼────┼──┼────┼──┼─────┼─────┤
│Ulipad    │有      │有      │WPDB│存盘时  │开源│          │★★★★★│
├─────┼────┼────┼──┼────┼──┼─────┼─────┤
│Eric      │有      │有      │类VC│存盘时  │开源│          │★★★★★│  
│          │        │        │    │        │    │          │(个人推荐)│
├─────┼────┼────┼──┼────┼──┼─────┼─────┤  
│BOA       │手动  │手动    │类VC│无      │开源│中文支持差│★★★    │
├─────┼────┼────┼──┼────┼──┼─────┼─────┤
│WingIDE   │有      │有      │类VC│手动    │共享│中文要设置│★★★★  │
├─────┼────┼────┼──┼────┼──┼─────┼─────┤
│Komodo    │无      │有      │类VC│手动    │共享│相当耗资源│★★★★  │
├─────┼────┼────┼──┼────┼──┼─────┼─────┤
│VIM+插件  │有   │无      │无  │无      │开源│          │★★★    │
├─────┼────┼────┼──┼────┼──┼─────┼─────┤
│emacs+插件│有   │无      │无  │无      │开源│          │★★★    │
├─────┼────┼────┼──┼────┼──┼─────┼─────┤
│eclipse+  │手动    │有      │类VC│手动    │开源│比较耗资源│★★★★  │
│pydev插件 │        │        │    │        │    │          │          │
├─────┴─┬──┼────┼──┼────┼──┼─────┼─────┤
│VS.Net 2003   │无  │有(很差)│类VC│无      │共享│兼容性很差│★(基本不 │
│+VisualPython │    │        │    │        │    │已停止维护│能用)     │
└───────┴──┴────┴──┴────┴──┴─────┴─────┘

除了PythonWin, VisualPython只支持Windows,其它都至少支持Win/Linux/Mac。
各项含义:
自动补全:变量/函数名打到一半时,提示可能的完整的变量/函数名。
智能感知:在库/类/对象后打"."后,提示可能的函数或变量。
调试:分四档,从好用到不好用分别为“类VC”(调试器操作方式与VC/eclipse相似),“WPDB”(使用WinPdb作为调试器),“用库”(要配合专门的python调试库,即要改代码来配合调试),最惨的当然是“无”啦。
语法检查:从好用到不好用分别为“存盘时”(存盘时自动检查,也可以在菜单里手动选择检查),“手动”(在菜单里选择检查),“无”(没有语法检查功能)
开源:分为开源,共享(提供免费试用,然后需要付费),收费三种。目前还没有“收费”这一类。
推荐度:五星为最推荐,一星为最不推荐。推荐度为作者主观评价,不代表其他人意见。

各IDE简介(注意本文最后修改时间是2008年7月):
IDLE:
装了python就会有这个,大家肯定都用过了,功能还凑合,调试器的使用方法和大家熟悉的eclipse/Visual Studio很不一样,需要学习和适应。各项表现都一般。推荐度:★★
PythonWin:
内 置Win32 extension,PythonWin成为了win32的python程序开发者必备的工具。虽然它只能运行在Win下,但其实也是开源的。功能上可以 认为它是加上了自动补全和智能感知功能的IDLE,虽然和以其它一些复杂的IDE相比有些差距,但却是轻量级Python IDE的首选。推荐度★★★
SPE:
全名Stani's Python Editor。相当不错的IDE,语法高亮、代码折叠、智能感知、自动语法检查等功能一应俱全,集成wxGlade。可惜没有自动补全功能。开源,可以用svn下载到最新的源代码,依赖wxPython。推荐度★★★★★
附:总有人说下不到SPE,去这里看看:
http://developer.berlios.de/project/showfiles.php?group_id=4161
SVN方式下载:
http://pythonide.blogspot.com/2007/02/how-to-download-latest-spe-from_26.html
Ulipad:
前身是NewEdit,和SPE相比,多了自动补全功能,因而比SPE更加方便,不过没有把界面设计器wxGlade集成进来。开源,可以用svn下载到最新的源代码,依赖wxPython。推荐度★★★★★。
Eric:
Eric 升级到4后,各方面有了很强的提升,全方位超过其它开源IDE。使用PyQt4作为图形库,界面美观大方,并与QtDesigner结合,使得开发GUI 程序变得非常方便,比下面将提到到BOA还要好用。最大的亮点莫过于它的调试器,支持断点设置