Friday, October 12, 2012

Design Pattern : Decorator 裝飾模式 (1)

Decorator

使用時機:
A.系統需要新增新功能,但不想用繼承造成系統的子類別過多。
B.類別需要「動態」附加新功能。

方法:
1.  定義一個Interface和實作它的Class。
2.  定義一個Abstract Class : Decorator 實作 interface。
3.  定義其他裝飾類別封裝實體化Decorator類別,並覆寫(override)原有的方法。
4.  使用裝飾類別~ 宣告並取代原有的物件。

範例:
假設一個遊戲中,主角可以拿槍射擊敵人。
所以我們定義一個槍的interface : IGun 和 class : CGun ,這是遊戲中最普通的槍。
隨著遊戲升級,武器可以加裝狙擊鏡Scope或是裝填雷射彈藥Laser ammo。
他們所對應的開火情況便不相同。


1.  定義一個Interface和實作它的Class。
/// <summary>
/// Abstract Class : CGun
/// </summary>
public interface IGun
{
    // 槍名
    String GunName { get; set;  }
    // 開火
    void Fire();
}

/// <summary>
    /// CGun實作IGun
    /// </summary>
    public class CGun : IGun
    {
        String sGunName;

        //建構子
        public CGun(String _GunName)
        {
            sGunName = _GunName;
        }

        // 槍名
        public String GunName
        {
            get { return sGunName; }
            set { sGunName = value; }
        }

        // 開火
        public void Fire()
        {
            Console.WriteLine(
                String.Format("{0}開火! ", sGunName));
        }
    }

2.  定義一個Abstract Class : Decorator 實作 interface。

/// <summary>
    /// 實作IGun 的 Decorator
    /// </summary>
   public abstract class Decorator : IGun
    {
        public String sGunName;
        protected CGun cGun = null;  //重要:需在此宣告一個protected CGun物件

        //透過建構子傳遞被修飾者
        public Decorator( CGun _cGun)
        {
            this.cGun = _cGun;
        }

        // 槍名
        public String GunName
        {
            get { return sGunName; }
            set { sGunName = value; }
        }

        //委託給被修飾者執行
        public virtual void Fire()
        {
            if (cGun != null)
            {
                this.cGun.Fire();
            }
        }
    }


3.  定義其他裝飾類別封裝實體化Decorator類別,並覆寫(override)原有的方法。

(A)
加裝狙擊鏡的裝飾類別
/// <summary>
    /// 可以加裝狙擊鏡的 裝飾類別
    /// </summary>
    public class CScopeDecorator : Decorator  //重要:實體化Decorator
    {
        //建構子 : 繼承基底類別的建構子
        public CScopeDecorator(CGun _cGun)
            : base(_cGun)
        {
            //建構子沒有變化...
        }

        //重寫父類別的Fire方法
        public override void Fire()
        {
            Console.WriteLine(
                String.Format("用裝了狙擊鏡的{0}開火! ", cGun.GunName ));
        }
}

(B)
裝填雷射彈藥的裝飾類別
/// <summary>
    /// 可以加裝雷射彈藥的 裝飾類別
    /// </summary>
    public class CLaserDecorator : Decorator
    {
        //建構子 : 繼承基底類別的建構子,但是改掉原本的槍名
        public CLaserDecorator(CGun _cGun)
            : base(_cGun)
        {
            //建構子有變化...
            _cGun.GunName = "Super Laser Rifle";
        }

        //重寫父類別的Fire方法
        public override void Fire()
        {
            Console.WriteLine(
                String.Format("用裝了雷射彈藥的{0}開火! ", cGun.GunName ));

            OverHeat();
        }

        //新增方法:槍管過熱
        private void OverHeat()
        {
            Console.WriteLine(
                String.Format("警告! {0} 槍管過熱。 ", cGun.GunName));
        }
}


4.  使用裝飾類別~ 宣告並取代原有的物件。


//宣告一個 CGun物件
IGun myGun = new CGun("Desert Eagle");
myGun.Fire();

//用CScopeDecorator 裝飾原本的 CGun物件
myGun = new CScopeDecorator((CGun)myGun);
myGun.Fire();

//用CLaserDecorator 裝飾原本的 CGun物件
IGun myGun2 = new CLaserDecorator
(
  new CGun("???")
);
   myGun2.Fire();


顯示結果
:

Desert Eagle
開火!
用裝了狙擊鏡的Desert Eagle開火!
用裝了雷射彈藥的Super Laser Rifle開火!
警告! Super Laser Rifle 槍管過熱。



Wednesday, October 3, 2012

Web AP在IIS的相關權限設定


Web 程式在本機上執行,通常寫事件檢視器和檔案的權限是預設為最高權限。
所以執行起來不會有什麼問題,但是一旦真正上到IIS後,才會開始發現一些問題,而大部分都是因為權限沒有設定好的關係。

可以先參考保哥這篇文章,超級推薦:

此篇文章針對以下兩個項目的寫入權限做說明。
1.      寫事件檢視器
2.      使用Log4Net寫檔



OS :Windows 2008 R2
IIS
版本: 7.5


★寫事件檢視器
如果看了保哥的文章,就知道IIS7.5集區會預設以 「ApplicationPoolIdentity」這個帳戶來執行。


所以我們只要把它加到有寫入/瀏覽
事件檢視器權限的群組: Event Log Readers

但是我們指定的帳戶名稱必須是: 「IIS AppPool\應用程式集區名稱」
這樣才能對應到要設定權限的集區。

 




我Web AP的集區名稱為ASP.NET v4.0,所以我就輸入使用者名稱:IIS AppPool\ASP.NET v4.0

檢查名稱後,系統就自動辨識了。 這支在IIS上的Web AP就有權限可以寫事件檢視器了。







★使用Log4Net寫檔

一般我們都是把log4net.xml , log4net.dll 和我們要寫入的檔案放在一起就可以寫檔了。
但是因為Web AP路徑的緣故,常常是程式讀取不到log4net.xml。
所以放在 AssemblyInfo.cs 的log4net設定字串,還是乖乖打上所在的資料夾名稱:「./App_Data/log4net.xml」

//log4net
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "./App_Data/log4net.xml", ConfigFileExtension = "xml", Watch = true)]


然後log4net.xml裡面設定的file value也是乖乖打上資料夾名稱:「./App_Data/Error.log」

<file value="./App_Data/Error.log" />


最後別忘了先新增Error.log,並把Error.log的讀寫權限打開。(因為是記錄檔&內部用,我就直接開Everyone了)