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

Mediator设计模式

Mediator中间人的意思,应用在多个类对象需要用一个作为中间人的类对象协调工作的时候。比如在信号灯坏掉的十字路口,单靠通行者之间的相互协调是很难正常通行的,因为很难做到让所有的人有相同的意识。如果有一个交警站在中间作为协调人,那么同行者之间的协调就能很好的执行。
多人参加的聊天室,聊天室类和参加者类之间的关系也是Mediator设计模式,参加者注册进聊天室,通过聊天室发送和接受消息,各个聊天参加者才能顺利的聊天。这个例子用Mediator设计模式实现如下:

/// Mediator 设计模式
class MainApp
{
static void Main()
{

//创建聊天室
Chatroom chatroom = new Chatroom();

//创建聊天室的参加者对象
Participant George = new Beatle("George");
Participant Paul = new Beatle("Paul");
Participant Ringo = new Beatle("Ringo");
Participant John = new Beatle("John");

//参加者进入聊天室
chatroom.Register(George);
chatroom.Register(Paul);
chatroom.Register(Ringo);
chatroom.Register(John);

//聊天室作为中间人,参加者向聊天对象发送消息。
Paul.Send("Ringo", "All you need is love");
Ringo.Send("George", "My sweet Lord");
Paul.Send("John", "Can't buy me love");
Paul.Send("Yoko", "Are you there?");

// Wait for user
Console.ReadKey();
}
}

//聊天室的抽象类,包含一个注册接口,发送消息接口。
abstract class AbstractChatroom
{
public abstract void Register(Participant participant);
public abstract void Send(string from, string to, string message);
}

//聊天室类
class Chatroom : AbstractChatroom
{
//加入聊天室的聊天者列
private Dictionary _participants =
new Dictionary();

//聊天者加入该聊天室。
public override void Register(Participant participant)
{
if (!_participants.ContainsValue(participant))
{
_participants[participant.Name] = participant;
}
participant.Chatroom = this;
}
//通过聊天室,将发送者的消息传送给接收者
public override void Send(
string from, string to, string message)
{
if (_participants.ContainsKey(to))
{
Participant participant = _participants[to];
if (participant != null)
{
participant.Receive(from, message);
}
}//如果接收者没有注册进聊天室,则系统提示。
else
{
Console.Write("From System: Cannot send a {0} (not exist)",to);
}
}
}
//聊天室参加者的抽象类
class Participant
{
private Chatroom _chatroom;
private string _name;

// Constructor
public Participant(string name)
{
this._name = name;
}
// Gets participant name
public string Name
{
get { return _name; }
}
// Gets chatroom
public Chatroom Chatroom
{
set { _chatroom = value; }
get { return _chatroom; }
}
// Sends message to given participant
public void Send(string to, string message)
{
_chatroom.Send(_name, to, message);
}
// Receives message from given participant
public virtual void Receive(
string from, string message)
{
Console.WriteLine("{0} to {1}: '{2}'", from, Name, message);
}
}
//聊天室参加者类
class Beatle : Participant
{
// Constructor
public Beatle(string name)
: base(name)
{
}
public override void Receive(string from, string message)
{
Console.Write("To a Beatle: ");
base.Receive(from, message);
}
}

执行结果:
To a Beatle: Paul to Ringo: 'All you need is love'
To a Beatle: Ringo to George: 'My sweet Lord'
To a Beatle: Paul to John: 'Can't buy me love'
From System: Cannot send a Yoko (not exist)

Observer观察者设计模式

Observer观察者设计模式,和计算机系统的中断的概念非常类似。CPU(作为观察者)对外部设备的变化,比如键盘的输入,鼠标的点击等,不是去不断的循环检测,而是当外部设备有变化时,主动产生一个中断,告诉CPU,这样就可以让CPU有更多的精力处理其他业务。
现实生活中,比如投资股票的投资者,一种方式是1整天的开盘时间都盯着股票的价格牌,另一种方式是通过一个观察者(比如手机短信),只有当价格变化的时候通知投资者,这样投资者就可以在股票没有变化的时候做其他事情。这就是Observer设计模式的概念。这个例子用程序实现如下:

/// Observer Design Pattern
class MainApp
{
static void Main()
{
//创建Google的股票,设定初始价格120.00
Google google = new Google("Google", 120);
//创建2位投资者,并且设定投资Google的股票。
google .Attach(new Investor("Tom"));
google .Attach(new Investor("Kate"));

//Google价格变动,主动通知投资者Tom和Kate
google .Price = 121;
google .Price = 122;
google .Price = 123;
google .Price = 124;
// Wait for user
Console.ReadKey();
}
}
//股票的抽象类
abstract class Stock
{
private string _symbol;//股票名称
private double _price;//股票价格
//投资者列
private List _investors = new List();

// Constructor
public Stock(string symbol, double price)
{
this._symbol = symbol;
this._price = price;
}
//投资该股票的投资者
public void Attach(IInvestor investor)
{
_investors.Add(investor);
}
//投资者退出投资该股票
public void Detach(IInvestor investor)
{
_investors.Remove(investor);
}
//股票价格变动的时候,通知所有投资该股票投资者
public void Notify()
{
foreach (IInvestor investor in _investors)
{
investor.Update(this);
}
Console.WriteLine("");
}

// 设置该股票的价格
public double Price
{
get { return _price; }
set
{
//触发价格更新事件
if (_price != value)
{
_price = value;
Notify();
}
}
}
// 取得股票名称
public string Symbol
{
get { return _symbol; }
}
}

//Google的股票类
class Google : Stock
{
// Constructor
public Google(string symbol, double price)
: base(symbol, price)
{
}
}
//投资者的接口
interface IInvestor
{
void Update(Stock stock);
}
//投资者类
class Investor : IInvestor
{
private string _name;
private Stock _stock;
// Constructor
public Investor(string name)
{
this._name = name;
}
//股票价格变动时,通知投资者更新股票价格
public void Update(Stock stock)
{
Console.WriteLine("Notified {0} of {1}'s " +
"change to {2:C}", _name, stock.Symbol, stock.Price);
}

// 投资者投资的股票。
public Stock Stock
{
get { return _stock; }
set { _stock = value; }
}
}

执行结果:
Notified Tom of Google's change to \121
Notified Kate of Google's change to \121

Notified Tom of Google's change to \122
Notified Kate of Google's change to \122

Notified Tom of Google's change to \123
Notified Kate of Google's change to \123

Notified Tom of Google's change to \124
Notified Kate of Google's change to \124