iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 3
3
Software Development

Learning Design Pattern in 30 real-case practices系列 第 3

謀略設計模式! 學習首重策略! (Strategy 策略模式)

Strategy 策略模式

需求描述

Amy(PO):

As a 資料分析者
I want 使用者在執行任一系統功能時,系統可以記錄使用記錄在文字檔
So that 我們可以知道使用者何時使用了該功能和次數

思考設計

JB:
這個User Story希望可以在系統將使用者行為記錄在文字檔,這是個很簡單的需求,我們開始來加入這項功能吧!

Lily:
記錄在文字檔不利於分析吧? 我覺得應該寫入到資料庫。

JB:
事實上,我們在iteration planning會議有提到這個問題,Amy說文字檔就足夠了。況且我們的資料庫設計的backlog還沒排進來,我想我們先在這個功能上保留一些彈性,你覺得如何設計比較好呢?

Lily:
我們可以建立兩個具體策略類別(Concrete strategy),分別實作文字檔和資料庫的記錄功能,在這個iteration先放上文字檔記錄的Strategy!

定義

定義多個演算法,各別封裝這些演算法,並讓它們可以互換 (Wiki)

定義策略的介面(也可建立為抽象類別):ILogger, 並分別建立兩個實作的具體策略類別:TextLoggerDbLogger

  • C#
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}");
}
  • Python
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的主程式決定,以利於隨時抽換。

  • C#
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()}");
    }
}
  • Python
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()));

主程式...

  • C#
//For current iteration
ILogger txtLogger = new TextLogger();
(new MyTask(txtLogger)).Run();

//Refine in next iteration
ILogger dbLogger = new DatabaseLogger();
(new MyTask(dbLogger)).Run();
  • Python
logger = TextLogger() #Current iteration
#logger = DbLogger() #Refine in next iteration
task = MyTask(logger)
task.run()

Source code

  1. C#
  1. Python

上一篇
[Design Pattern] 準備開發環境
下一篇
雞同鴨講也可以通! (Interpreter 解譯器模式)
系列文
Learning Design Pattern in 30 real-case practices30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言