网站用什么语言开发,seo应该怎么做,兖州那有做网站的,互联网公司黑话动机(Motivate):在软件构建 过程中#xff0c;我们需要为某些对象建立一种“通知依赖关系” --------一个对象#xff08;目标对象#xff09;的状态发生改变#xff0c;所有的依赖对象#xff08;观察者对象#xff09;都将得到通知。如果这样的依赖关系过于紧密#x… 动机(Motivate): 在软件构建 过程中我们需要为某些对象建立一种“通知依赖关系” --------一个对象目标对象的状态发生改变所有的依赖对象观察者对象都将得到通知。如果这样的依赖关系过于紧密将使软件不能很好地抵御变化。使用面 向对象技术可以将这种依赖关系弱化并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。意图(Intent): 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。 -------《设计模式》GOF结构图(Struct): 适用性 1当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。 2当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。 3当一个对象必须通知其它对象而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。生活中的例子 观 察者定义了对象间一对多的关系当一个对象的状态变化时所有依赖它的对象都得到通知并且自动地更新。在ATM取款当取款成功后以手机、邮件等方式进行通知。 代码实现 1 public class BankAccount 2 { 3 Emailer emailer; //强信赖关系 4 Mobile phoneNumber; //强信赖关系 5 6 private double _money; 7 8 public Emailer Emailer 9 {10 get { return emailer; }11 set { this.emailer value; }12 }13 public Mobile PhoneNumber14 {15 get { return phoneNumber; }16 set { this.phoneNumber value; }17 }18 public double Money19 {20 get { return _money; }21 set { this._money value; }22 }23 24 public void WithDraw()25 {26 emailer.SendEmail(this);27 phoneNumber.SendNotification(this);28 }29 30 } 1 public class Emailer 2 { 3 private string _emailer; 4 public Emailer(string emailer) 5 { 6 this._emailer emailer; 7 } 8 public void SendEmail(BankAccount ba) 9 {10 //..11 Console.WriteLine(Notified : Emailer is {0}, You withdraw {1:C} , _emailer, ba.Money);12 }13 } 1 public class Mobile 2 { 3 private long _phoneNumber; 4 public Mobile(long phoneNumber) 5 { 6 this._phoneNumber phoneNumber; 7 } 8 public void SendNotification(BankAccount ba) 9 {10 Console.WriteLine(Notified :Phone number is {0} You withdraw {1:C} , _phoneNumber, ba.Money);11 }12 } 此时简单的客户端调用如下 1 class Test 2 { 3 static void Main(string[] args) 4 { 5 BankAccount ba new BankAccount(); 6 Emailer emailer new Emailer(abcdwxc163.com); 7 Mobile mobile new Mobile(13901234567); 8 ba.Emailer emailer; 9 ba.PhoneNumber mobile;10 ba.Money 2000; 11 ba.WithDraw();12 }13 } 运行结果如下 由此可见程序可以正常运行但请注意BandAccount和Emailer及Mobile之间形成了一种双向的依赖关系即BankAccount调用了Emailer及Mobile的方法而Emailer及Mobile调用了BnadAccount类的属性。如果有其中一个类变化有可能会引起另一个的变化。如果又需添加一种新的通知方式就得在BankAccount的WithDraw()方法中增加对该中通知方式的调用。 显然这样的设计极大的违背了“开放-封闭”原则这不是我们所想要的仅仅是新增加了一种通知对象就需要对原有的BankAccount类进行修改这样的设计是很糟糕的。对此做进一步的抽象既然出现了多个通知对象我们就为这些对象之间抽象出一个接口用它来取消BankAccount和具体的通知对象之间依赖。 由此我们由左图转换到右图。 实例代码如下 1 public interface IObserverAccount2 {3 void Update(BankAccount ba);4 } 1 public class BankAccount 2 { 3 IObserverAccount emailer; //依赖于接口 4 IObserverAccount phoneNumber; //依赖于接口 5 6 private double _money; 7 8 public IObserverAccount Emailer 9 {10 get { return emailer; }11 set { this.emailer value; }12 }13 public IObserverAccount PhoneNumber14 {15 get { return phoneNumber; }16 set { this.phoneNumber value; }17 }18 public double Money19 {20 get { return _money; }21 set { this._money value; }22 }23 24 public void WithDraw()25 {26 emailer.Update(this);27 phoneNumber.Update(this);28 }29 30 } 1 public class Emailer : IObserverAccount 2 { 3 private string _emailer; 4 public Emailer(string emailer) 5 { 6 this._emailer emailer; 7 } 8 public void Update(BankAccount ba) 9 {10 //..11 Console.WriteLine(Notified : Emailer is {0}, You withdraw {1:C} , _emailer, ba.Money);12 }13 } 1 public class Mobile : IObserverAccount 2 { 3 private long _phoneNumber; 4 public Mobile(long phoneNumber) 5 { 6 this._phoneNumber phoneNumber; 7 } 8 public void Update(BankAccount ba) 9 {10 Console.WriteLine(Notified :Phone number is {0} You withdraw {1:C} , _phoneNumber, ba.Money);11 }12 } 客户端与上方相同其运行结果也相同。但BankAccount增加和删除通知对象时还需对其进行修改。对此我们再做如下重构在BankAccount中维护一个IObserver列表同时提供相应的维护方法。 1 public class BankAccount 2 { 3 private ListIObserverAccount Observers new ListIObserverAccount(); 4 5 6 private double _money; 7 8 public double Money 9 {10 get { return _money; }11 set { this._money value; }12 }13 14 public void WithDraw()15 {16 foreach (IObserverAccount ob in Observers)17 {18 ob.Update(this);19 20 }21 }22 public void AddObserver(IObserverAccount observer)23 {24 Observers.Add(observer);25 }26 public void RemoverObserver(IObserverAccount observer)27 {28 Observers.Remove(observer);29 }30 31 } 此时客户端代码如下 1 class Test 2 { 3 static void Main(string[] args) 4 { 5 BankAccount ba new BankAccount(); 6 IObserverAccount emailer new Emailer(abcdwxc163.com); 7 IObserverAccount mobile new Mobile(13901234567); 8 9 ba.Money 2000;10 ba.AddObserver(emailer);11 ba.AddObserver(mobile);12 13 ba.WithDraw();14 }15 } 走到这一步已经有了Observer模式的影子了BankAccount类不再依赖于具体的Emailer或Mobile而是依赖于抽象的IObserverAccount。存在着的一个问题是Emailer或Mobile仍然依赖于具体的BankAccount解决这样的问题很简单只需要再对BankAccount类做一次抽象。如下图 1 public abstract class Subject 2 { 3 private ListIObserverAccount Observers new ListIObserverAccount(); 4 5 private double _money; 6 public Subject(double money) 7 { 8 this._money money; 9 }10 11 public double Money12 {13 get { return _money; }14 }15 16 public void WithDraw()17 {18 foreach (IObserverAccount ob in Observers)19 {20 ob.Update(this);21 22 }23 }24 public void AddObserver(IObserverAccount observer)25 {26 Observers.Add(observer);27 }28 public void RemoverObserver(IObserverAccount observer)29 {30 Observers.Remove(observer);31 }32 33 } 1 public interface IObserverAccount2 {3 void Update(Subject subject);4 } 1 public class BankAccount : Subject2 {3 public BankAccount(double money)4 : base(money)5 { }6 7 } 1 public class Emailer : IObserverAccount 2 { 3 private string _emalier; 4 public Emailer(string emailer ) 5 { 6 this._emalier emailer; 7 } 8 public void Update(Subject subject) 9 { 10 Console.WriteLine(Notified : Emailer is {0}, You withdraw {1:C} , _emalier, subject.Money);11 }12 } 1 public class Mobile : IObserverAccount 2 { 3 private long _phoneNumber; 4 public Mobile(long phoneNumber) 5 { 6 this._phoneNumber phoneNumber; 7 } 8 public void Update(Subject subject) 9 {10 Console.WriteLine(Notified :Phone number is {0} You withdraw {1:C} , _phoneNumber, subject.Money);11 }12 } 此时客户端实现如下 1 class Test 2 { 3 static void Main(string[] args) 4 { 5 Subject subject new BankAccount(2000); 6 subject.AddObserver(new Emailer(abcdwxc163.com)); 7 subject.AddObserver(new Mobile(13901234567)); 8 9 subject.WithDraw();10 }11 } 推模式与拉模式 对于发布-订阅模型大家都很容易能想到推模式与拉模式用SQL Server做过数据库复制的朋友对这一点很清楚。在Observer模式中同样区分推模式和拉模式我先简单的解释一下两者的区别推模式是当有消息时把消息信息以参数的形式传递推给所有观察者而拉模式是当有消息时通知消息的方法本身并不带任何的参数是由观察者自己到主体对象那儿取回拉消息。知道了这一点大家可能很容易发现上面我所举的例子其实是一种推模式的Observer模式。我们先看看这种模式带来了什么好处当有消息时所有的 观察者都会直接得到全部的消息并进行相应的处理程序与主体对象没什么关系两者之间的关系是一种松散耦合。但是它也有缺陷第一是所有的观察者得到的 消息是一样的也许有些信息对某个观察者来说根本就用不上也就是观察者不能“按需所取”第二当通知消息的参数有变化时所有的观察者对象都要变化。鉴于以上问题拉模式就应运而生了它是由观察者自己主动去取消息需要什么信息就可以取什么不会像推模式那样得到所有的消息参数。 拉模式实现如下 1 public abstract class Subject 2 { 3 private ListIObserverAccount Observers new ListIObserverAccount(); 4 5 6 private double _money; 7 8 public double Money 9 {10 get { return _money; } 11 }12 public Subject(double money)13 {14 this._money money;15 }16 public void WithDraw()17 {18 foreach (IObserverAccount ob in Observers)19 {20 ob.Update();21 22 }23 }24 public void AddObserver(IObserverAccount observer)25 {26 Observers.Add(observer);27 }28 public void RemoverObserver(IObserverAccount observer)29 {30 Observers.Remove(observer);31 }32 33 } 1 public interface IObserverAccount2 {3 void Update();4 } 1 public class BankAccount :Subject2 {3 public BankAccount(double money)4 : base(money)5 { }6 7 } 1 public class Emailer : IObserverAccount 2 { 3 private string _emalier; 4 private Subject _subject; 5 public Emailer(string emailer,Subject subject) 6 { 7 this._emalier emailer; 8 this._subject subject; 9 }10 public void Update()11 {12 //..13 Console.WriteLine(Notified : Emailer is {0}, You withdraw {1:C} , _emalier,_subject.Money);14 }15 } 1 public class Mobile : IObserverAccount 2 { 3 private long _phoneNumber; 4 private Subject _subject; 5 public Mobile(long phoneNumber,Subject subject) 6 { 7 this._phoneNumber phoneNumber; 8 this._subject subject; 9 }10 public void Update()11 {12 Console.WriteLine(Notified :Phone number is {0} You withdraw {1:C} , _phoneNumber,_subject.Money);13 }14 } 此时客户端调用如下 1 class Test 2 { 3 static void Main(string[] args) 4 { 5 Subject subject new BankAccount(2000); 6 subject.AddObserver(new Emailer(abcdwxc163.com,subject)); 7 subject.AddObserver(new Mobile(13901234567,subject)); 8 9 subject.WithDraw();10 }11 } .NET中Observer实现 用事件和委托来实现Observer模式我认为更加的简单和优雅也是一种更好的解决方案。 1 public class Subject 2 { 3 public event NotifyEventHandler NotifyEvent; 4 5 private double _money; 6 public Subject(double money) 7 { 8 this._money money; 9 }10 11 public double Money12 {13 get { return _money; }14 }15 16 public void WithDraw()17 {18 OnNotifyChange();19 }20 public void OnNotifyChange()21 {22 if (NotifyEvent ! null)23 {24 NotifyEvent(this);25 }26 27 }28 29 } 1 public class Emailer 2 { 3 private string _emalier; 4 public Emailer(string emailer) 5 { 6 this._emalier emailer; 7 } 8 public void Update(object obj) 9 {10 if (obj is Subject)11 {12 Subject subject (Subject)obj;13 14 Console.WriteLine(Notified : Emailer is {0}, You withdraw {1:C} , _emalier, subject.Money);15 }16 }17 } public delegate void NotifyEventHandler(object sender); 客户端调用如下 1 class Test 2 { 3 static void Main(string[] args) 4 { 5 Subject subject new Subject(2000); 6 Emailer emailer new Emailer(abcdwxc163.com); 7 subject.NotifyEvent new NotifyEventHandler(emailer.Update); 8 9 10 subject.WithDraw();11 }12 } Observer实现要点: 1使用面向对象的抽象Observer模式使得我们可以独立地改变目标与观察者从而使二者之间的依赖关系达到松耦合。 2目标发送通知时无需指定观察者通知可以携带通知信息作为参数会自动传播。观察者自己决定是否需要订阅通知。目标对象对此一无所知。 3在C#中的Event。委托充当了抽象的Observer接口而提供事件的对象充当了目标对象委托是比抽象Observer接口更为松耦合的设计。 #9楼 2007-12-25 16:08 wycg_cnh20 拉模式和推模式的差别在概念上讲得很清楚,但是,从代码上没看出推和拉的差别来/ 支持(0) 反对(0) #12楼 2009-04-17 14:30 soxyunyi 是否体现推拉是由观察者类的update方法参数决定的。 支持(0) 反对(0) #13楼 2009-04-17 14:34 soxunyi public void update(Observable obs, Object arg) 这是Java中Obersver接口方法 如果在方法体中通过obs来获取主题的状态变化则是拉模式 如果在方法体中通过arg来获取主题的状态变化则是推模式。 因为通过obs获取是在观察者类中实现的故为拉。 而arg则是由主题类传递给观察者的故为推。