现在的位置: 首页 > 综合 > 正文

设计模式-观察者模式

2012年11月17日 ⁄ 综合 ⁄ 共 5155字 ⁄ 字号 评论关闭

     观察者模式允许我们观察应用程序中一个对象的状态。最好的理解它的方式就是 Publish/ Subscribe 模式。
在观察者模式中有被观察的叫subject,一些观察subject 的对象叫观察者。该模式是松耦合的一个非常好的实例
因为我们的类可以依赖很少的信息进行交互。

subject 需要被三件事关注:
1. 注册一个观察者
2. 删除一个观察者
3. 通知事件的观察者

      比方说我们准备创建一个video game, 在我们的游戏中,我们有一些非玩家角色,这些角色依赖于玩家。
为了该需要,我们假设我们有一个弓箭手类和一个击剑手类,如果玩家在范围内,弓箭手类能够进行攻击,
如果玩家已经被关闭,那么击剑手类就能够进行攻击。那么,我们如何应用观察者模式实现这样的控制呢。

      这是一个很好的应用观察者模式的例子。 在这里 玩家就是 subject .  玩家没有任何概念关于有多少非玩家角色在
观察它。有意思是这都没有关系,因为我们正在广播玩家的位置给关心玩家的非玩家角色。
这里我们采用的是 2维模式。因为计算两点间的距离比较容易。

      为了实现观察者模式,我们先创建两个接口,第一个为subject.  Subject 需要能够注册观,删除,通知 观察者。
在这个实例中,观察者要基于subject (玩家) 的位置去尝试进行攻击。下面是定义的接口。

    namespace Observer
    
{
        
public interface ISubject
        
{
            
void RegisterObserver(IObserver observer);
            
void UnregisterObserver(IObserver observer);
            
void NofifyObservers();
        }


        
public interface IObserver
        
{
            
void Attack(ref Position p);
        }

    }

      我们需要创建一个帮助类来表示角色的位置. 这个类也包含两个方法来计算两个点间的距离。在这个类里的每个事
都应该能被自解释的... 即使你已经对几何生疏了,你也必须相信我正确的计算了两点间的距离。:)

 namespace Observer
   
{
     
public class Position
       
{
          
private int _x;
          
private int _y;
     
          
public int X
          
{
            
get return _x; }
            
set { _x = value; }
         }

         
public int Y
         
{
            
get return _y; }
            
set { _y = value; }
         }

  
         
public Position()
         
{
            _x 
= _y = 0;
         }

         
public Position(int x, int y)
         
{
            _x 
= x;
            _y 
= y;
         }

    
         
// This could be done on 1 line, but I broke
         
// it apart for readability.
         public double CalcDistance(Position pos)
         
{
            
int xsquared = (this.X - pos.X) * (this.X - pos.X);
            
int ysquared = (this.Y - pos.Y) * (this.Y - pos.Y);
            
int sum = xsquared + ysquared;
            
return Math.Sqrt(Convert.ToDouble(sum));
         }

    
         
public override string ToString()
         
{
            
return _x.ToString() + “, “ + _y.ToString();
         }

      }

   }

     我们要把规则简化,我们要有两个类,射箭手类和击剑手类。我们假设一个弓箭手只能在距离
玩家四到十个单元的范围内攻击玩家。一个击剑手必须在两个单元格内攻击玩家。我们创建一个
玩家,它必须实作ISubject 接口,因为它要做为 subject . 玩家也要有一个属性表明我们当前
的位置.

 namespace Observer
    
{
       
public class Player : ISubject
      
{
          
private List<IObserver> _observers;
          
private Position _currentPosition;
          
          
public Position CurrentPosition
          
{
            
get return _currentPosition; }
            
set { _currentPosition = value; }
         }

         
public List<IObserver> Observers
         
{
            
get return _observers; }
         }

    
         
// We initialize our observer list in the constructor.
         public Player()
         
{
            _observers 
= new List<IObserver>();
         }

    
         
// This is the key event in our scenario.  The only thing
         
// that the observers care about is the position of the 
         
// player, so we notify them when it changes.
         public void SetPosition(Position pos)
         
{
            _currentPosition 
= pos;
            Console.WriteLine(“Player 
is at “ + pos.ToString());
            NofifyObservers();
         }

    
         
// This is our function to register a new observer.
         public void RegisterObserver(IObserver observer)
         
{
            
if (!_observers.Contains(observer))
               _observers.Add(observer);
         }

    
         
// This takes an observer out of the list.
         public void UnregisterObserver(IObserver observer)
         
{
            
if (_observers.Contains(observer))
               _observers.Remove(observer);
         }

    
         
// This does the notification.  In our case
         
// that means each observer will try to attack
         
// based on the position of the player.
         public void NofifyObservers()
         
{
            
foreach (IObserver obs in _observers)
               obs.Attack(
ref _currentPosition);
         }

      }

   }


      我们已经建立subject . 现在我们需要实现几个观察者,注意到,RegisterObserver  方法和
UnregisterObserver  方法 只是简单的从有效的观察者内部列表里添加和删除观察者。这些
方法都传递一个IObserver 参数,这意味着它们会接受任何实现IObserver  接口的对象。NotifyObserver
方法简单的轮循观察者列表,并且调用每一个对象的Attack 方法。我们知道每一个观察者都有
这样的方法,因为在IObserver 接口内被指定了。

      之前提到过,我们实现了两个观察者为这个实例,弓箭手类和击剑手类,下面是它们的实现:

 namespace Observer
    
{
       
public class Archer : IObserver
       
{
          
private string _name;
          
private Position _current;
          
public string Name
          
{
             
get return _name; }
            
set { _name = value; }
         }

         
public Position Current
         
{
            
get return _current; }
            
set { _current = value; }
         }

    
         
public Archer(string name)
         
{
            _name 
= name;
            _current 
= new Position(00);
         }

    
         
public void SetPosition(Position pos)
         
{
            _current 
= pos;
         }

    
         
public void Attack(ref Position p)
         
{
            
// Archer can attack if use is between 4 and 10
            
// units away.
            double distance = p.CalcDistance(_current);
            
string formatted = String.Format(“{0:0.00}”, distance); 
            
if (distance >= 4 && distance <= 10)
               Console.WriteLine(_name 
                  
+ ” is attacking! [” + formatted + “]”);

抱歉!评论已关闭.