2015年2月21日 星期六

C# Design Pattern - Observer Pattern 觀察者模式

觀察者模式是一種軟件設計圖案,其中一個對象,稱為主體,保持其家屬,稱為觀察者的列表,並且自動通知它們中的任何狀態變化,通常通過調用其方法之一。它主要用於實現分佈式事件處理系統。 Observer模式也是大家熟悉的模型 - 視圖 - 控制器(MVC)架構模式的一個關鍵組成部分。[1]觀察者模式在眾多的編程庫和系統,包括幾乎所有的GUI工具包來實現。

物件導向設計建議我們將系統切割成一群互相協同合作的物件,以便提高個別物件的可重用性。在這種做法之下,有些物件的狀態與行為會相依於其他物件,並需要因為其他物件的狀態改變而做出反應。

觀察者模式可能會導致內存洩漏,遺失Listener的問題,因為在基本實現它需要顯式註冊和註銷明確,如在Dispose模式,因為主體持有以觀察員強引用,保持它們活著。這可以由對象保持到觀察者弱引用被防止。





如何得知物件狀態改變?

物件狀態異動的頻率無法預料。
為了達到狀態一致性而將物件緊密耦合在一起,將會降低物件的重複使用性。
不能限制資料相依物件的個數,可能有任意數量的物件都有興趣想要知道物件的狀態。
當某物件狀態改變時,其相依物件必須適時自動被通知。


Solution:定義一對多的相依關係,當物件改變狀態的時候,讓它的相依者可以自動收到更新通知。此模式規範了兩種角色(介面):擁有狀態的物件(Subject)以及它的相依者(Observer),也就是想得知Subject狀態改變的物件們(Observer可以有一個以上)。

Subject角色允許Observer向它註冊或取消註冊(attach、detach),以便獲得或解除狀態改變的通知。當Subject要將狀態改變的事實通知Observer的時候,Subject會呼叫自己的notify方法通知Observer。Observer角色需實作update方法,以便讓Subject在notify方法中可以通知到各種不同類別的Observer(ConcreteObserver)。

下面範例的結構代碼演示了其註冊的對象通知和更新的狀態變化Observer模式。

using System;
using System.Collections.Generic;

namespace DoFactory.GangOfFour.Observer.Structural
{
  /// <summary>
  /// Observer Design Pattern.
  /// </summary>
  class MainApp
  {
    /// <summary>
    /// 程式進入控制台應用程序的起始。
    /// </summary>
    static void Main()
    {
      // 配置 Observer pattern
      ConcreteSubject s = new ConcreteSubject();

      s.Attach(new ConcreteObserver(s, "X"));
      s.Attach(new ConcreteObserver(s, "Y"));
      s.Attach(new ConcreteObserver(s, "Z"));

      // 改變主題和通知觀察者群
      s.SubjectState = "ABC";
      s.Notify();

      // 等待User
      Console.ReadKey();
    }
  }

  /// <summary>
  /// 'Subject' abstract 的 class
  /// </summary>
  abstract class Subject
  {
    private List<Observer> _observers = new List<Observer>();

    public void Attach(Observer observer)
    {
      _observers.Add(observer);
    }

    public void Detach(Observer observer)
    {
      _observers.Remove(observer);
    }

    public void Notify()
    {
      foreach (Observer o in _observers)
      {
        o.Update();
      }
    }
  }

  /// <summary>
  /// 'ConcreteSubject' 的 class
  /// </summary>
  class ConcreteSubject : Subject
  {
    private string _subjectState;

    //  subject state的存取
    public string SubjectState
    {
      get { return _subjectState; }
      set { _subjectState = value; }
    }
  }

  /// <summary>
  ///  'Observer' 的 abstract class
  /// </summary>
  abstract class Observer
  {
    public abstract void Update();
  }

  /// <summary>
  /// 'ConcreteObserver' 的 class
  /// </summary>
  class ConcreteObserver : Observer
  {
    private string _name;
    private string _observerState;
    private ConcreteSubject _subject;

    // 建構函數
    public ConcreteObserver(
      ConcreteSubject subject, string name)
    {
      this._subject = subject;
      this._name = name;
    }

    public override void Update()
    {
      _observerState = _subject.SubjectState;
      Console.WriteLine("Observer {0}'s new state is {1}",
        _name, _observerState);
    }

    //  subject存取
    public ConcreteSubject Subject
    {
      get { return _subject; }
      set { _subject = value; }
    }
  }
}


下面的程式範例用真實情況來呈現,程式碼演示中,以Microsoft註冊的投資者被告知每一個股票的價值發生變化時觀察者模式。

using System;
using System.Collections.Generic;

namespace DoFactory.GangOfFour.Observer.RealWorld
{
  /// <summary>
  /// Observer Design Pattern.
  /// </summary>
  class MainApp
  {
    /// <summary>
    /// 程式進入控制台應用程序的起始。
    /// </summary>
    static void Main()
    {
      // 產生 Microsoft stock 和 附上 投資者群
      Microsoft microsoft = new Microsoft("Microsoft", 120.00);
      microsoft.Attach(new Investor("Sorros"));
      microsoft.Attach(new Investor("Berkshire"));

      // 價格波動會通知投資者
      microsoft.Price = 120.10;
      microsoft.Price = 121.00;
      microsoft.Price = 120.50;
      microsoft.Price = 120.75;

      // 等待User
      Console.ReadKey();
    }
  }

  /// <summary>
  /// The 'Subject' abstract class
  /// </summary>
  abstract class Stock
  {
    private string _symbol;
    private double _price;
    private List<IInvestor> _investors = new List<IInvestor>();

    // 建構函數
    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("");
    }

    //  price存取
    public double Price
    {
      get { return _price; }
      set
      {
        if (_price != value)
        {
          _price = value;
          Notify();
        }
      }
    }

    // 取得 symbol
    public string Symbol
    {
      get { return _symbol; }
    }
  }

  /// <summary>
  /// 'ConcreteSubject' 的 class
  /// </summary>
  class Microsoft : Stock
  {
    // 建構函數
    public Micrososft(string symbol, double price)
      : base(symbol, price)
    {
    }
  }

  /// <summary>
  /// 'Observer' 的 interface
  /// </summary>
  interface IInvestor
  {
    void Update(Stock stock);
  }

  /// <summary>
  /// 'ConcreteObserver' class
  /// </summary>
  class Investor : IInvestor
  {
    private string _name;
    private Stock _stock;

    // 建構函數
    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);
    }

    // 變數 stock 的存取
    public Stock Stock
    {
      get { return _stock; }
      set { _stock = value; }
    }
  }

}

-雲遊山水為知已逍遙一生而忘齡- 電腦神手

2015年2月10日 星期二

C# Sorting Algorithm - Bubble Sort 泡泡演算法

我們經常使用排序算法來排序數字和字符串。另外,我們有很多的排序算法。在這裡用一些簡單的範例解釋如何用泡泡排序算法的產生來了解此演算法是如何運作的。

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {

      static int BubbleSort()
        {
            Console.Write("\n程序數值使用冒泡排序升序");
            Console.Write("\n\n輸入元素的總數: ");
            int max = Convert.ToInt32(Console.ReadLine());

            int [] numarray = new int[max];

            for(int i = 0; i < max; i++)
            {
                Console.Write("\n輸入 [" + (i + 1).ToString() + "] 元素: ");
                numarray[i] = Convert.ToInt32(Console.ReadLine());
            }

            Console.Write("排序之前   : ");
            for(int k = 0; k < max; k++)
                Console.Write(numarray[k] + " ");
            Console.Write("\n");

            for(int i = 1; i < max; i++)
            {
                for(int j = 0; j < max - i; j++)
                {
                    if(numarray[j] > numarray[j + 1])
                    {
                        int temp = numarray[j];
                        numarray[j] = numarray[j + 1];
                        numarray[j + 1] = temp;
                    }
                }
                Console.Write("迴圈之後 " + i.ToString() + ": ");
                for(int k = 0; k < max; k++)
                    Console.Write(numarray[k] +  " ");
                Console.Write("/*** " + (i + 1).ToString() + " 最大的數值被放人Array的最後 ***/\n");
            }

            Console.Write("\n\n在上升的順序號碼如下:\n\n");
            for(int i = 0; i < max; i++)
            {
                Console.Write("Sorted [" + (i + 1).ToString() + "] 元素: ");
                Console.Write(numarray[i]);
                Console.Write("\n");
            }
            return 0;
        } 

      static void Main(string[] args)
      {
            BubbleSort();
          
      }
    }

}

可以用上面的程式去跑看看來看結果。

-雲遊山水為知已逍遙一生而忘齡- 電腦神手