2010年1月29日星期五

Windows下使用 getopt 函数

wingetopt.h


/*
POSIX getopt for Windows

AT&T Public License

Code given out at the 1985 UNIFORUM conference in Dallas.
*/

#ifdef __GNUC__
#include
#endif
#ifndef __GNUC__

#ifndef _WINGETOPT_H_
#define _WINGETOPT_H_

#ifdef __cplusplus
extern "C" {
#endif

extern int opterr;
extern int optind;
extern int optopt;
extern char *optarg;
extern int getopt(int argc, char **argv, char *opts);

#ifdef __cplusplus
}
#endif

#endif /* _GETOPT_H_ */
#endif /* __GNUC__ */



wingetopt.c

/*
POSIX getopt for Windows

AT&T Public License

Code given out at the 1985 UNIFORUM conference in Dallas.
*/

#ifndef __GNUC__

#include "wingetopt.h"
#include

#define NULL 0
#define EOF (-1)
#define ERR(s, c) if(opterr){\
char errbuf[2];\
errbuf[0] = c; errbuf[1] = '\n';\
fputs(argv[0], stderr);\
fputs(s, stderr);\
fputc(c, stderr);}
//(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
//(void) write(2, s, (unsigned)strlen(s));\
//(void) write(2, errbuf, 2);}

int opterr = 1;
int optind = 1;
int optopt;
char *optarg;

int
getopt(argc, argv, opts)
int argc;
char **argv, *opts;
{
static int sp = 1;
register int c;
register char *cp;

if(sp == 1)
if(optind >= argc ||
argv[optind][0] != '-' || argv[optind][1] == '\0')
return(EOF);
else if(strcmp(argv[optind], "--") == NULL) {
optind++;
return(EOF);
}
optopt = c = argv[optind][sp];
if(c == ':' || (cp=strchr(opts, c)) == NULL) {
ERR(": illegal option -- ", c);
if(argv[optind][++sp] == '\0') {
optind++;
sp = 1;
}
return('?');
}
if(*++cp == ':') {
if(argv[optind][sp+1] != '\0')
optarg = &argv[optind++][sp+1];
else if(++optind >= argc) {
ERR(": option requires an argument -- ", c);
sp = 1;
return('?');
} else
optarg = argv[optind++];
sp = 1;
} else {
if(argv[optind][++sp] == '\0') {
sp = 1;
optind++;
}
optarg = NULL;
}
return(c);
}

#endif /* __GNUC__ */

2009年11月8日星期日

通过例子学习Ajax的处理过程

下面是演示一个利用Ajax技术,读取服务器上的一个HTML文件数据显示在WebPage上的例子。在例子中加了详细的注释。
为了简化过程,服务器端没有应用任何CGI,通过这个例子,可以看到Ajax处理的一般过程:
WebPage通过JavaScript调用Ajax处理函数--->(函数内)根据不同的浏览器创建XMLHttpRequest对象--->为其onreadystatechange设置回调函数--->在回调函数中判断状态,OK时将数据显示到WebPage内。
演示:
http://homepage3.nifty.com/myinfo/ajax.html


<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>ajax test</title>
<script language="javascript"><!--
//函数;取得指定服务器上文件的数据。文件名通过参数pageURL指定。
function getPage(pageURL) {
//创建XMLHttpRequest对象,是Ajax的灵魂。
xmlhttp = createXMLHttp();
if (xmlhttp)
{
//设置一个回调函数setPageData ,当状态改变的时候调用。
xmlhttp.onreadystatechange = setPageData;
//用Get方式取得数据。
xmlhttp.open('GET', pageURL);
//通过Get方式取得数据的时候,send(null)即可。如果通过Post方式的时候,要指定具体的参数
//比如:xmlhttp.send("nickname="encodeURL(document.sampleForm.nickname.value));
xmlhttp.send(null);
}else{
alert("XMLHttpRequest Fail.");
}
}
//供回调用的函数。
function setPageData()
{
//当XMLHttpRequest对象取得数据完毕且状态是200(OK)的时候
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
//将数据设置到WebPage
document.getElementById("disp").innerHTML = xmlhttp.responseText;
}
}
//创建XMLHttpRequest对象
function createXMLHttp()
{
try {
//微软系列浏览器的时候
return new ActiveXObject ("Microsoft.XMLHTTP");
}catch(e){
try {
//非微软系列浏览器的时候。
return new XMLHttpRequest();
}catch(e) {
return null;
}
}
//创建不成功则返回Null
return null;
}
// --></script>
</head>
<body>
<form>
<!-- 点击网页上的Form按钮,调用getPage函数 -->
<input type="button" value="Page 1" onClick="getPage('1.html')">
<input type="button" value="Page 2" onClick="getPage('2.html')">
<input type="button" value="Page 3" onClick="getPage('3.html')">
</form>
<div id="disp"></div>
</body>
</html>

2009年11月3日星期二

Facade设计模式

Facade[f'sɑ:d],建筑物的外观的意思。在程序开发中,会有很多小的类,他们之间的关系错综复杂,如果想完成一件任务,需要了解这些类的关系和调用顺序才行。将这些错综复杂的类关系用Facade类包装起来,对外提供一个窗口,就是Facade设计模式。
比如顾客(Customer)申请房屋抵押贷款,怎样根据顾客的身份和申请贷款的金额来判断能否批准,需要做非常复杂的手续:先调用银行类(Bank),判断是不是有足够的存款,然后调用信用评定类(Credit),判断是不是有足够的信用等级,然后调用借款类Loan,判断是不是有坏账。如果把这些复杂的评定手续包装到一个Morgate类,只对外提供一个IsEligible窗口,判断一个顾客能否批注贷款,就非常的方便。这个例子用程序实现如下:

class MainApp
{
//Test
static void Main()
{
// Facade
Mortgage mortgage = new Mortgage();
//创建一个顾客:Tom
Customer customer = new Customer("Tom");
//判断是否能提供抵押贷款
bool eligible = mortgage.IsEligible(customer, 125000);

Console.WriteLine("\n" + customer.Name +

" has been " + (eligible ? "Approved" : "Rejected"));
// Wait for user
Console.ReadKey();
}
}
//银行类
class Bank
{
public bool HasSufficientSavings(Customer c, int amount)
{
Console.WriteLine("Check bank for " + c.Name);
return true;
}
}
//信用评定类
class Credit
{
public bool HasGoodCredit(Customer c)
{

Console.WriteLine("Check credit for " + c.Name);
return true;
}
}
//以往贷款记录类
class Loan
{
public bool HasNoBadLoans(Customer c)
{
Console.WriteLine("Check loans for " + c.Name);
return true;
}
}
//顾客类
class Customer
{
private string _name;
// Constructor
public Customer(string name)
{
this._name = name;
}
// Gets the name
public string Name
{
get { return _name; }
}
}
//Facade类
class Mortgage
{
private Bank _bank = new Bank();
private Loan _loan = new Loan();
private Credit _credit = new Credit();
//对外提供的窗口
public bool IsEligible(Customer cust, int amount)
{
Console.WriteLine("{0} applies for {1:C} loan\n",
cust.Name, amount);
bool eligible = true;
// 具体评定能否贷款的手续
if (!_bank.HasSufficientSavings(cust, amount))
{
eligible = false;
}
else if (!_loan.HasNoBadLoans(cust))
{
eligible = false;
}
else if (!_credit.HasGoodCredit(cust))
{
eligible = false;
}
return eligible;
}
}

执行结果:
Check bank for Tom
Check loans for Tom
Check credit for Tom

Tom has been Approved

Flyweight设计模式

思想是共用创建的对象,如果对象被已经存在就不不重复创建,减轻程序负担,实现轻量化。
比如在网页上显示多幅图片的时候,为了减轻服务器负担,不是每一幅都从服务器上Download,而是同样的图片只生成一次,然后在不同的地方显示,在实现上,一般用对象工厂的方式,具体是否创建对象由工厂判断决定。
这个例子用Flyweight设计模式实现如下:

/// Flyweight Design Pattern.
class MainApp
{
static void Main()
{
FlyweightFactory factory = new FlyweightFactory();

// 用对象工厂取得“山”的图片
Flyweight f1 = factory.GetFlyweight("山");
//在坐标1,2处显示该图片
f1.Display(1,2);
// 用对象工厂取得“水”的图片
Flyweight f2 = factory.GetFlyweight("水");
//在坐标1,3处显示该图片
f2.Display(1, 3);
// 用对象工厂取得“山”的图片 因为前边已经存在山的图片,对象工厂会直接返回已有图片而不是再创建。
Flyweight f3 = factory.GetFlyweight("山");
//在坐标1,4处显示该图片
f3.Display(1, 4);

// Wait for user
Console.ReadKey();
}
}
/// FlyweightFactory,如果某图片已经生成(flyweights表中存在),则不重复创建。
class FlyweightFactory
{
private Hashtable flyweights = new Hashtable();
// Constructor
public FlyweightFactory()
{
}
//根据图片的名字,取得图片对象。
public Flyweight GetFlyweight(string name)
{
//如果Hash表中不存在该图片则创建。
if (flyweights[name] == null)
{
flyweights.Add(name, new ImageFlyweight(name));
}
return ((Flyweight)flyweights[name]);
}
}
///图片类的抽象类
abstract class Flyweight
{
public abstract void Display(int x, int y);
}
//图片类,提供Display显示图片的方法。
class ImageFlyweight : Flyweight
{
string _name;
public ImageFlyweight(string name)
{
_name = name;
}
public override void Display(int x, int y)
{
Console.WriteLine(string.Format("坐标{0},{1}处显示 {2}", x, y, _name));
}
}

Interpreter 设计模式

Interpreter 解释器,如同普通的Basic语言等的解释器一样,一边读入语言(字符串),一边解释执行。Interpreter 设计模式就是用来解决这种需要边读入边解释程序的设计模式。
罗马数字的表示规则如下:

罗马数字共有7个,即Ⅰ(1),Ⅴ(5),Ⅹ(10),Ⅼ(50),Ⅽ(100),Ⅾ(500),Ⅿ(1000)。按照下述的规则可以表示任意正整数。*需要注意的是罗马数字中没有“0”。

重复数次:1个罗马数字重复几次,就表示这个数的几倍。
右加左减:
在一个较大的罗马数字的右边记上一个较小的罗马数字,表示大数字加小数字。
在一个较大的罗马数字的左边记上一个较小的罗马数字,表示大数字减小数字。
但是,左减不能跨越一个位数。比如,99不可以用ⅠⅭ表示,而是用ⅩⅭⅠⅩ表示。(等同于阿拉伯数字每位数字分别表示)
例如:999 = 900+90+9 = ⅭⅯ+ⅩⅭ+ⅠⅩ = ⅭⅯⅩⅭⅠⅩ
此外,左减数字不能超过1位,比如8写成ⅤⅠⅠⅠ,而非ⅠⅠⅩ。
同理,右加数字不能超过3位,比如14写成ⅩⅠⅤ,而非ⅩⅠⅠⅠⅠ。
加线乘千:在1个罗马数字的上方加上1条横线或者在右下方写Ⅿ,表示将这个数乘以1000,即是原数的1000倍。
同理,如果上方有2条横线,即是原数的1000000倍。
例外:由于ⅠⅤ是古罗马神话主神朱庇特(IVPITER,古罗马字母没有J和U)的首字,因此有时用ⅠⅠⅠⅠ代替ⅠⅤ。
[编辑] 示例
Ⅰ - 1 unus
ⅠⅠ - 2 duo
ⅠⅠⅠ - 3 tres
ⅠⅤ - 4 quattuor
Ⅴ - 5 quinque
ⅤⅠ - 6 sex
ⅤⅠⅠ - 7 septem
Ⅾ - 500
ⅮⅤⅠ - 506
ⅮⅬⅤ - 555
ⅮⅭⅬⅩⅤⅠ - 666
ⅮⅭⅭⅬⅩⅩⅤⅠⅠ - 777
ⅮⅭⅭⅭⅬⅩⅩⅩⅤⅠⅠⅠ - 888
Ⅿ - 1,000
ⅯⅭ - 1,100
ⅯⅭⅭ - 1,200
ⅯⅭⅭⅭ - 1,300

用解释器模式实现的将罗马字符串转化为数值的程序如下:

class MainApp
{
///

/// Interpreter设计模式,将罗马字符串转化成数值。
static void Main()
{
string roman = "MCMLXXX";
Context context = new Context(roman);
// Build the 'parse tree'

List tree = new List();
tree.Add(new ThousandExpression());
tree.Add(new HundredExpression());
tree.Add(new TenExpression());
tree.Add(new OneExpression());
// Interpret
foreach (Expression exp in tree)
{
exp.Interpret(context);
}
Console.WriteLine("{0} = {1}", roman, context.Output);
// Wait for user
Console.ReadKey();
}
}
//内容类,要解释的对象类。
class Context
{
private string _input;
private int _output;
//构造函数,用字符串(要解释的语言)初始化。
public Context(string input)
{
this._input = input;
}
// 取得或者设置输入值
public string Input
{
get { return _input; }
set { _input = value; }
}
// 取得或者设置输出值
public int Output
{
get { return _output; }
set { _output = value; }
}
}
//抽象的表达式类,对表达式进行解释
abstract class Expression
{
//对context的内容进行解释。
public void Interpret(Context context)
{
if (context.Input.Length == 0)
return;
if (context.Input.StartsWith(Nine()))
{
context.Output += (9 * Multiplier());
context.Input = context.Input.Substring(2);
}
else if (context.Input.StartsWith(Four()))
{
context.Output += (4 * Multiplier());
context.Input = context.Input.Substring(2);
}
else if (context.Input.StartsWith(Five()))
{
context.Output += (5 * Multiplier());
context.Input = context.Input.Substring(1);
}
while (context.Input.StartsWith(One()))
{
context.Output += (1 * Multiplier());
context.Input = context.Input.Substring(1);
}
}
//抽象函数,在具体类中重新
public abstract string One();
public abstract string Four();
public abstract string Five();
public abstract string Nine();
public abstract int Multiplier();

}
//终结符表达式类,用来检查罗马数字:M
class ThousandExpression : Expression
{
public override string One() { return "M"; }
public override string Four() { return " "; }
public override string Five() { return " "; }
public override string Nine() { return " "; }
public override int Multiplier() { return 1000; }
}
//终结符表达式类,用来检查罗马数字:C, CD, D or CM
class HundredExpression : Expression
{
public override string One() { return "C"; }
public override string Four() { return "CD"; }
public override string Five() { return "D"; }
public override string Nine() { return "CM"; }
public override int Multiplier() { return 100; }
}
//终结符表达式类,用来检查罗马数字:X, XL, L and XC
class TenExpression : Expression
{
public override string One() { return "X"; }
public override string Four() { return "XL"; }
public override string Five() { return "L"; }
public override string Nine() { return "XC"; }
public override int Multiplier() { return 10; }
}

//终结符表达式类,用来检查罗马数字:I, II, III, IV, V, VI, VI, VII, VIII, IX
class OneExpression : Expression
{
public override string One() { return "I"; }
public override string Four() { return "IV"; }
public override string Five() { return "V"; }
public override string Nine() { return "IX"; }
public override int Multiplier() { return 1; }

}

执行结果:
MCMLXXX= 1980

Command设计模式

Command设计模式是将发起请求的对象和处理请求分离开的设计模式,由 Invoker ,Command, Receiver 三个类构成。Invoker接收到用户发起的事件后,生成一个Command对象,通过调用Command对象的方法处理事件。Command定义了事件处理的具体过程,Receiver是具体处理的执行者。
假设Receiver是能干很多家务的执行者,比如扫地,做饭,交水电费等等。

public class Receiver
{
//Action1和Action2是做家务
public void Action1()
{
Console.WriteLine("扫地");
}
public void Action2()
{
Console.WriteLine("洗衣服");
}

//Action3和Action4是去交费
public void Action3()
{
Console.WriteLine("交水费");
}
public void Action4()
{
Console.WriteLine("交电费");
}
}

如果直接对他行命令,比如做家务,或者交费,这需要对类进行如下的修改,通过传递给doit一个参数,来命令具体动作。

public class Receiver
{
//Action1和Action2是做家务
public void Action1()
{
Console.WriteLine("扫地");
}
public void Action2()
{
Console.WriteLine("洗衣服");
}

//Action3和Action4是去交费
public void Action3()
{
Console.WriteLine("交水费");
}
public void Action4()
{
Console.WriteLine("交电费");
}

public void doit(int type)
{
if(type == 1) //做家务
{
Action1();
Action2();
}
if(type == 2) //去交费
{
Action3();
Action4();
}
}
}

但是这样存在一个问题,如果想命令他扫地和交水费,则需要修改类内部的if条件,当条件非常复杂时,这样的修改会变得非常不灵活。
而用command设计模式,将Receiver通过命令Command包装后,让Invoker调用,实现了命令的发起者Invoker和命令的执行者Receiver通过Command隔离开,提供了更多的灵活性。用Command设计模式实现如下:

//受信者
//接收命令做相应的处理。
public class Receiver
{
//Action1和Action2是做家务
public void Action1()
{
Console.WriteLine("扫地");
}
public void Action2()
{
Console.WriteLine("洗衣服");
}

//Action3和Action4是去交费
public void Action3()
{
Console.WriteLine("交水费");
}
public void Action4()
{
Console.WriteLine("交电费");
}
}

//抽象的命令类
public abstract class Command
{
protected Receiver res;

//将Receiver在构造函数中设置好
public Command(Receiver res)
{
this.res = res;
}
//Invoker中调用
public abstract void Execute();
}

//命令类(做家务)
public class ConcreteCommand_Task : Command
{
public ConcreteCommand_Task(Receiver res)
: base(res)
{
}

public override void Execute()
{
this.res.Action1();
this.res.Action2();
}
}

//命令类(去交费)
public class ConcreteCommand_TaskPay : Command
{
public ConcreteCommand_TaskPay(Receiver res)
: base(res)
{
}

public override void Execute()
{
this.res.Action3();
this.res.Action4();
}
}

//命令执行者
public class Invoker
{
private Command com;

//通过属性设置命令
public Command SetCommand
{
set { this.com = value; }
}

//让命令对象去执行命令
public void ExecuteCommand()
{
com.Execute();
}
}
class Class1
{
static void Main(string[] args)
{
//受信者(命令实际执行者)
Receiver res = new Receiver();

//实际的命令对象
//家务命令
ConcreteCommand_Task task = new ConcreteCommand_Task(res);
//交费命令
ConcreteCommand_TaskPay pay = new ConcreteCommand_TaskPay(res);

//命令者
Invoker invoker = new Invoker();

//命令者执行设置的命令
invoker.SetCommand = task;
invoker.ExecuteCommand();

invoker.SetCommand = pay;
invoker.ExecuteCommand();
}
}
}

2009年11月2日星期一

Memento纪念品设计模式

事件的发起者Originator想将某个特定的状态作为纪念品memento保存起来,目的是为了将来可以随时恢复到这个状态,这就是Memento设计模式的概念。
打电脑游戏的时候,因为游戏很难在短时间内打完,所以希望能在想退出游戏的时候将游戏的状态保存,等有时间的时候,再恢复游戏的状态继续玩,假设我们只需要保存游戏的:时间,地点,进度这3个参数(一般我们只保存能恢复类状态的最少信息),就可以恢复游戏。这个例子用Memento设计模式实现如下:

/// Memento 设计模式
class MainApp
{
///

/// Entry point into console application.

///


static void Main()
{

//创建游戏
Game g1 = new Game();
g1.Time = "2009/10/18 10:12:15";
g1.Position = "123,113";
g1.Score = 18000;

// 保存游戏状态
ProspectMemory m = new ProspectMemory();
m.Memento = g1.SaveMemento();

//退出游戏
g1 = null;

//重新创建游戏
Game g2 = new Game();

// 恢复游戏状态
g2.RestoreMemento(m.Memento);

// Wait for user
Console.ReadKey();

}

}
//Originator:游戏类
class Game
{
private string _time;//时间
private string _position;//地点
private double _score;//得分数

public string Time
{
get { return _time; }
set
{
_time = value;
Console.WriteLine("Time: " + _time);
}
}
public string Position
{
get { return _position; }
set
{
_position = value;
Console.WriteLine("Position: " + _position);
}
}
public double Score
{
get { return _score; }
set
{
_score = value;
Console.WriteLine("Score: " + _score);
}
}

// 保存状态, 返回一个纪念品
public Memento SaveMemento()
{
Console.WriteLine("\nSaving state --\n");
return new Memento(_time, _position, _score);
}
// 恢复状态,用纪念品
public void RestoreMemento(Memento memento)
{
Console.WriteLine("\nRestoring state --\n");
this.Time = memento.Time;
this.Position = memento.Position;
this.Score = memento.Score;
}
}

//纪念品类
class Memento
{
private string _time;
private string _position;
private double _score;

// Constructor
public Memento(string time, string position, double progress)
{
this._time = time;
this._position = position;
this._score = progress;
}
// Gets or sets Time
public string Time
{
get { return _time; }
set { _time = value; }
}
// Gets or set Position
public string Position
{
get { return _position; }
set { _position = value; }
}
// Gets or sets Score
public double Score
{
get { return _score; }
set { _score = value; }
}
}
//Caretaker类,封装了memento的实例对象。
class ProspectMemory
{
private Memento _memento;
// Property
public Memento Memento
{
set { _memento = value; }
get { return _memento; }
}
}

执行结果如下:
Time: 2009/10/18 10:12:15
Position: 123,113
Score: 18000

Saving state --

Restoring state --

Time: 2009/10/18 10:12:15
Position: 123,113
Score: 18000