---
# System prepended metadata

title: Pattern-Strategy
tags: [Code Sense, Design-Pattern]

---

###### tags: `Code Sense` `Design-Pattern`

# Pattern-Strategy

## 簡介

近期開始整理之前所用Pattern，Strategy為Pattern使用常見的一種，屬於Behavioral Patterns的其中一種

> Behavioral design patterns are concerned with algorithms and the assignment of responsibilities between objects.

策略一般使用情境在於若方法在實作上有所不同，則會宣告介面分別讓物件去實作。而我們要換實作方法時，直接可在Context則可直接抽換或者在DI直接做抽換。

## 使用情境與實作

近期寫國家儀器溝通時看到一段程式碼，原本儀器溝通使用的方法是GPIB溝通，後續加了Usb溝通方式，Gpib溝通使用的是Ni的Vias dll檔的MessageBasedSession Class而Usb溝通方式使用Ni N4882 dll檔的Device Class。

以前寫結構化程式的自己直覺會直接的使用變數去切換溝通，如下述程式第5行，結果就會看到在每個方法都需要做一次判斷(29,43行)。如果此時又多一個新的溝通方式，例如TCP，則我們則須對此NormalBaseDevice做大調整(每個function都需要更動)


```=

public class NormalBaseDevice
{

    private bool IsGpib;

    // Gpib Com
    MessageBasedSession GpibCom;
    
    // Usb Com
    Device UsbCom;
    
    public NormalBaseDevice(bool isGPIB)
    {

        IsGpib = isGPIB;

            if (isGPIB)
            {
                GpibCom = new MessageBasedSession();
            }
            else
            {
                UsbCom = new Device();
            }

        }

        public string Write(string cmd)
        {

            if (IsGpib)
            {
                return GpibCom.Write(cmd);
            }
            else
            {
                return UsbCom.Write(cmd);
            }

        }

        public int Read()
        {

            if (IsGpib)
            {
                return GpibCom.Read();
            }
            else
            {
                return UsbCom.Read();
            }

        }

    }

```

這種寫法讓所有溝通方法耦合在一起，若要做調整必然有一定程度的影響。此時我們可以以介面去做隔離，讓每種溝通方法去實作介面，在Context使用上就可直接做調整。

我們先宣告一IStrategy介面，宣告Wirte與Read的介面方法如下

```=
public interface IStrategy
{
    string Write(string cmd);

    int Read();
}
```

接著撰寫GpibCom與UsbCom Concrete class並實作IStrategy方法。

```=
public class GpibCom : IStrategy
{
    private MessageBasedSession Device;

    public GpibCom()
    {
        Device = new MessageBasedSession();
    }

    public string Write(string cmd)
    {
        return Device.Write(cmd);
         
    }

    public int Read()
    {
        return Device.Read();
    }
}
```


```=
 public class UsbCom : IStrategy
{
    private Device Device;

    public UsbCom()
    {
        Device = new Device();
    }

    public string Write(string cmd)
    {
        return Device.Write(cmd);
    }

    public int Read()
    {
        return Device.Read();
    }
}
```

此時我們在Context就可以隨意抽換我們要的方法，如下

```=
class Program
{
     static void Main(string[] args)
    {
        IStrategy com;
        
        com = new GpibCom();
        var cmd = com.Write(Action);
        
        com = new UsbCom();
        var cmd = com.Write(Action);
        
    }
}

```

另外，策略一般很常搭簡單工廠去包裝Switch選擇要實體化哪個物件。如下

```=

public class ComFacotry
{
    public enum ComType { Gpib, Usb}

    public static IStrategy CreateCom(ComType type)
    {
        IStrategy com;

        switch (type)
        {
            case ComType.Gpib:
                com = new GpibCom();
                break;
                
            default:
                com = new UsbCom();
                break;

        }

        return com;
    }
}
```

Context使用則變變成


```=
class Program
{
     static void Main(string[] args)
    {
        var usbCom = ComFacotry.CreateCom(ComType.Usb);
        var cmd = usbCom.Write(Action);
    }
}

```

[SourceCode](https://github.com/spyua/hackmdDocCode.git) in CSharpDummyPratice/CSharpDummyCode/DesignPattern/Strategy/