2009年5月22日 星期五

抽象化的好處

最近拜讀「深入淺出-設計模式」一書後,常常很有感觸,

對於物件導向程式設計的觀念懂得還是太短淺了!

以前寫程式時很少考慮程式的擴充性與元件和元件的耦合力問題,常常會有牽一髮動全身的感覺!囧...

哈~~好像有點離題太遠了,主要是最近看了工廠方法模式(Factory Method Pattern)的架構以後,

才知道原來 abstract 的功用這麼大。首先,先來看一下 abstract 可以在何處何時使用以及其用途,

abstract 修飾詞可以運用在類別、方法、屬性、索引子 (Indexer) 和事件,

從字面上我們可以知道它的用途是將宣告的內容抽象化,讓實際繼承的類別能夠實作其內容。

工廠方法模式的定義為定義一個建立物件的介面,由實作的類別決定要實體化哪一個物件。

不過這邊我並沒有藉由子類別產出的物件讓介面控制物件的操作,而是固定丟回字串產出,

在這邊繼承的類別(XMLEventLogSaverHTMLEventLogSaver)實作抽象的內容即可完成運作,程式碼不僅可重覆利用,也能解決當流程變動時,

需要重覆修改兩個以上的方法。

abstract class EventLogSaver
{
protected string path;
protected Progress op;

public void GenerateReport()
{
int BUFF_SIZE = 1024;
EventLog ev = new EventLog("Application");

EventLogEntryCollection collection = ev.Entries;
op.SetMaximum(collection.Count);
StreamWriter writer = new StreamWriter(path, false, System.Text.Encoding.UTF8, BUFF_SIZE);
writer.WriteLine(getHeader());

foreach(EventLogEntry entry in collection)
{
writer.WriteLine(getRowData(entry));
op.Add();
}
writer.WriteLine(getFooter());
writer.Flush();
writer.Close();
op.Done();
}

public string HTMLEncode(string v)
{
return v.Replace("<", "<").Replace(">", ">");
}

abstract protected string getHeader();
abstract protected string getRowData(EventLogEntry entry);
abstract protected string getFooter();
}

經由上面的定義,我們如果有不同類態的顯示方式,

我們只要透過改寫 getHeadergetRowData 以及 getFooter 三個方法就能夠達成目的。

詳細的程式碼如下所示:

interface Progress
{
void SetMaximum(int max);
void Add();
void Done();
}

class ObserverProgress: Progress
{
ProgressBar pb;
public ObserverProgress(ProgressBar pb)
{
this.pb = pb;
pb.Minimum = 0;
pb.Value = 0;
}

public void SetMaximum(int max)
{
pb.Maximum = max;
}

public void Add()
{
pb.Increment(1);
}

public void Done()
{
MessageBox.Show("寫入完成");
}

}

class NullProgress:Progress
{
public NullProgress()
{
}
public void SetMaximum(int max)
{
//set nothing;
}
public void Add()
{
//Add nothing;
}
public void Done()
{
Console.WriteLine("寫入完成");
}
}
class XMLEventLogSaver : EventLogSaver
{
public XMLEventLogSaver(string path, Progress op)
{
this.path = path;
this.op = op;
}

protected override string getHeader()
{
return "<?xml version=\"1.0\"?>"+
"<?xml-stylesheet type=\"text/xsl\" href=\"eventlog.xsl\" ?><glossary>";
}

protected override string getRowData(EventLogEntry entry)
{
return
String.Format("<item><category>{0}</category><date> {1}<date>"+
"<time>{2}</time><source>{3}</source><classification>"+
"{4}</classification><event>{5}</event><user>{6}<user>"+
"<computer>{7}</computer><description>{8}</description></item>",
entry.Category, entry.TimeWritten.ToString("yyyy/MM/dd"),
entry.TimeWritten.ToString("hh:mm:ss"), entry.Source, entry.EntryType.ToString(),
entry.EventID, entry.UserName, entry.MachineName, HTMLEncode(entry.Message));
}

protected override string getFooter()
{
return "</glossary>";
}
}

class HTMLEventLogSaver : EventLogSaver
{
public HTMLEventLogSaver(string path, Progress op)
{
this.path = path;
this.op = op;
}

protected override string getHeader()
{
return "<table border=1>" + String.Format(
"<tr><td>{0}</td><td>{1}</td><td>{2}</td>"+
"<td>{3}</td><td>{4}</td><td>{5}</td><td>{6}</td>"+
"<td>{7}</td><td>{8}</td></tr>",
"類型", "日期", "時間", "來源", "類別", "事件", "使用者", "電腦", "描述");
}

protected override string getRowData(EventLogEntry entry)
{
return
String.Format(
"<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td>" +
"<td>{5}</td><td>{6}</td><td>{7}</td><td>{8}</td></tr>",
entry.EntryType.ToString(), entry.TimeWritten.ToString("yyyy/MM/dd"),
entry.TimeWritten.ToString("hh:mm:ss"), entry.Source, entry.Category,
entry.EventID.ToString(), entry.UserName, entry.MachineName, HTMLEncode(entry.Message));
}

protected override string getFooter()
{
return "</table>";
}
}

abstract class EventLogSaver
{
protected string path;
protected Progress op;

public void GenerateReport()
{
int BUFF_SIZE = 1024;
EventLog ev = new EventLog("Application");

EventLogEntryCollection collection = ev.Entries;
op.SetMaximum(collection.Count);
StreamWriter writer = new StreamWriter(path, false, System.Text.Encoding.UTF8, BUFF_SIZE);
writer.WriteLine(getHeader());

foreach(EventLogEntry entry in collection)
{
writer.WriteLine(getRowData(entry));
op.Add();
}
writer.WriteLine(getFooter());
writer.Flush();
writer.Close();
op.Done();
}

public string HTMLEncode(string v)
{
return v.Replace("<", "<").Replace(">", ">");
}

abstract protected string getHeader();
abstract protected string getRowData(EventLogEntry entry);
abstract protected string getFooter();
}

沒有留言:

張貼留言