Amy(PO):
As a 資料分析者
I want 使用者在執行任一系統功能時,系統可以記錄使用記錄在文字檔
So that 我們可以知道使用者何時使用了該功能和次數
JB:
這個User Story希望可以在系統將使用者行為記錄在文字檔,這是個很簡單的需求,我們開始來加入這項功能吧!
Lily:
記錄在文字檔不利於分析吧? 我覺得應該寫入到資料庫。
JB:
事實上,我們在iteration planning會議有提到這個問題,Amy說文字檔就足夠了。況且我們的資料庫設計的backlog還沒排進來,我想我們先在這個功能上保留一些彈性,你覺得如何設計比較好呢?
Lily:
我們可以建立兩個具體策略類別(Concrete strategy),分別實作文字檔和資料庫的記錄功能,在這個iteration先放上文字檔記錄的Strategy!
定義多個演算法,各別封裝這些演算法,並讓它們可以互換 (Wiki)
定義策略的介面(也可建立為抽象類別):ILogger
, 並分別建立兩個實作的具體策略類別:TextLogger
和DbLogger
。
public interface ILogger
{
void Debug(string msg);
void Warn(string msg);
void Error(string msg);
}
public class TextLogger:ILogger
{
public void Debug(string msg) => System.Diagnostics.Trace.WriteLine($"(Text)Debug: {msg}");
public void Warn(string msg) => System.Diagnostics.Trace.WriteLine($"(Text)Warn: : {msg}");
public void Error(string msg) => System.Diagnostics.Trace.WriteLine($"(Text)Error: : {msg}");
}
public class DbLogger:ILogger
{
public void Debug(string msg) => System.Diagnostics.Trace.WriteLine($"(Database)Debug: {msg}");
public void Warn(string msg) => System.Diagnostics.Trace.WriteLine($"(Database)Warn: : {msg}");
public void Error(string msg) => System.Diagnostics.Trace.WriteLine($"(Database)Error: : {msg}");
}
from abc import ABC, abstractmethod
class BaseLogger(ABC):
@abstractmethod
def debug(self):
pass
@abstractmethod
def warn(self):
pass
@abstractmethod
def error(self):
pass
class TextLogger(BaseLogger):
def debug(self,msg):
print("(Text)Debug: " + msg)
def warn(self,msg):
print("(Text)Warn: " + msg)
def error(self,msg):
print("(Text)Error: " + msg)
class DbLogger(BaseLogger):
def debug(self,msg):
print("(Database)Debug: " + msg)
def warn(self,msg):
print("(Database)Warn: " + msg)
def error(self,msg):
print("(Database)Error: " + msg)
將ILogger
作為其他類別的建構參數,如此我們可以在該類別進行記錄的動作。
但是實體化,亦即決定要記錄在文字檔或者資料庫則由建立MyTask
的主程式決定,以利於隨時抽換。
public class MyTask
{
private ILogger _logger = null;
public MyTask(ILogger logger)
{
if (logger != null)
this._logger = logger;
else
throw new ArgumentNullException("logger");
}
public void Run()
{
//Do something
this._logger.Debug($"My task was done on {DateTime.Now.ToString()}");
}
}
from BaseLogger import BaseLogger
from time import gmtime, strftime
class MyTask:
def __init__(self,logger=BaseLogger):
if logger is None:
raise TypeError
else:
self._logger = logger
def run(self):
self._logger.warn("My task was done on " + strftime("%Y-%m-%d %H:%M:%S", gmtime()));
主程式...
//For current iteration
ILogger txtLogger = new TextLogger();
(new MyTask(txtLogger)).Run();
//Refine in next iteration
ILogger dbLogger = new DatabaseLogger();
(new MyTask(dbLogger)).Run();
logger = TextLogger() #Current iteration
#logger = DbLogger() #Refine in next iteration
task = MyTask(logger)
task.run()