設計模式之策略模式(工業控制)

寫這篇文章的原因是:對於工業自動化上位機的編寫,策略類在硬件調用的應用是相當多的。
網上很多關於策略模式的教程,簡單的實現可以自行參考;
https://blog.csdn.net/alexhu2010q/article/details/102501561
這裏就不做贅述了。

簡單實現步驟

switch封裝(原始狀態)
case的抽象類提取
case子類的建立
多態實例的調用(實現成功狀態)

說好處(讓你有看下去的衝動)

  1. 兼容多種運動控制卡,無論增加多少種,代碼都是可維護的,一個類能保證不超過500Line。
  2. 方便後期維護,能快速尋找Bug,修改過程不用擔心破壞代碼結構。

爲什麼會有上述好處

說白了就是符合SOLID設計基本原則,單一功能、開閉原則、里氏替換、接口隔離以及依賴反轉。不是王婆賣瓜自賣自誇,是確實很多公司是使用Switch case的原始寫法。

原始寫法

/*****************************************************
** 命名空間: ConsoleApp2
** 文 件 名:AxisCard
** 內容簡述:
** 版    本:V1.0
** 創 建 人:Byron
** 創建日期:2020/3/31 18:28:32
** 修改記錄:
日期        版本      修改人    修改內容   
*****************************************************/

namespace ConsoleApp2
{
    public class AxisCard
    {
        public CardTypeEnum cardType = CardTypeEnum.NULL;
        public bool initSuccess = false;

        public void Print(string cmd)
        {
            System.Diagnostics.Debug.WriteLine(cmd);
        }

        public void InitCard(CardTypeEnum cardType)
        {
            this.cardType = cardType;
            switch (cardType)
            {
                case CardTypeEnum.研華:
                    Print("研華控制卡初始化成功");
                    initSuccess = true;
                    break;
                case CardTypeEnum.雷賽:
                    Print("雷賽控制卡初始化成功");
                    initSuccess = true;
                    break;
                case CardTypeEnum.衆爲興:
                    Print("衆爲興控制卡初始化成功");
                    initSuccess = true;
                    break;
            }
        }

        /// <summary>
        /// 移動軸
        /// </summary>
        /// <param name="axisNum"></param>
        /// <param name="pos"></param>
        public void AxisMoveAbs(int axisNum, double pos)
        {
            switch (cardType)
            {
                case CardTypeEnum.研華:
                    Print("研華控制卡移動" + pos);
                    initSuccess = true;
                    break;
                case CardTypeEnum.雷賽:
                    Print("雷賽控制卡移動" + pos);
                    initSuccess = true;
                    break;
                case CardTypeEnum.衆爲興:
                    Print("衆爲興控制卡移動" + pos);
                    initSuccess = true;
                    break;
            }
        }

        /// <summary>
        /// 獲取單個輸出
        /// </summary>
        /// <param name="IOindex"></param>
        /// <returns></returns>
        public bool GetInput(int IOindex)
        {
            switch (cardType)
            {
                case CardTypeEnum.研華:
                    return true;
                case CardTypeEnum.雷賽:
                    return true;
                case CardTypeEnum.衆爲興:
                    return true;
            }
            return false;
        }
    }

    public enum CardTypeEnum
    {
        NULL,
        臺達,
        研華,
        雷賽,
        衆爲興,
        ByronCard,
        //************************
    }
}

寫了一小段,個人比較懶,不想列出太多,這種寫法增加了我的惰性;、

改進後寫法

case的抽象類提取

/*****************************************************
** 命名空間: ConsoleApp2
** 文 件 名:ICard
** 內容簡述:
** 版    本:V1.0
** 創 建 人:Byron
** 創建日期:2020/3/31 18:47:47
** 修改記錄:
日期        版本      修改人    修改內容   
*****************************************************/

namespace ConsoleApp2.Card
{
    /// <summary>
    /// 卡接口
    /// </summary>
    internal interface ICard
    {
        void InitCard();
        void AxisMoveAbs(int axisNum, double pos);
        bool GetInput(int Ioindex);
    }
}

case子類的建立

/*****************************************************
** 命名空間: ConsoleApp2
** 文 件 名:雷賽Card
** 內容簡述:
** 版    本:V1.0
** 創 建 人:Byron
** 創建日期:2020/3/31 18:50:49
** 修改記錄:
日期        版本      修改人    修改內容   
*****************************************************/

namespace ConsoleApp2.Card
{
    internal class 雷賽Card : ICard
    {
        public void Print(string cmd)
        {
            System.Diagnostics.Debug.WriteLine(cmd);
        }
        public void AxisMoveAbs(int axisNum, double pos)
        {
            Print("雷賽卡軸移動" + pos);
        }

        public bool GetInput(int Ioindex)
        {
            Print("獲取雷賽卡IO");
            return true;
        }

        public void InitCard()
        {
            Print("雷賽卡初始化");
        }
    }
}

/*****************************************************
** 命名空間: ConsoleApp2
** 文 件 名:雷賽Card
** 內容簡述:
** 版    本:V1.0
** 創 建 人:Byron
** 創建日期:2020/3/31 18:50:49
** 修改記錄:
日期        版本      修改人    修改內容   
*****************************************************/

namespace ConsoleApp2.Card
{
    internal class 研華Card : ICard
    {
        public void Print(string cmd)
        {
            System.Diagnostics.Debug.WriteLine(cmd);
        }
        public void AxisMoveAbs(int axisNum, double pos)
        {
            Print("研華卡軸移動" + pos);
        }

        public bool GetInput(int Ioindex)
        {
            Print("獲取研華卡IO");
            return true;
        }

        public void InitCard()
        {
            Print("研華卡初始化");
        }
    }
}

/*****************************************************
** 命名空間: ConsoleApp2
** 文 件 名:雷賽Card
** 內容簡述:
** 版    本:V1.0
** 創 建 人:Byron
** 創建日期:2020/3/31 18:50:49
** 修改記錄:
日期        版本      修改人    修改內容   
*****************************************************/

namespace ConsoleApp2.Card
{
    internal class 衆爲興Card : ICard
    {
        public void Print(string cmd)
        {
            System.Diagnostics.Debug.WriteLine(cmd);
        }
        public void AxisMoveAbs(int axisNum, double pos)
        {
            Print("衆爲興卡軸移動" + pos);
        }

        public bool GetInput(int Ioindex)
        {
            Print("獲取衆爲興卡IO");
            return true;
        }

        public void InitCard()
        {
            Print("衆爲興卡初始化");
        }
    }
}

多態實例的調用(實現成功狀態)

這裏實現不自覺的用上了簡單工廠模式,不是有意的,後面有機會會出一篇簡單工廠在工業控制的應用。

/*****************************************************
** 命名空間: ConsoleApp2.Card
** 文 件 名:CardContext
** 內容簡述:
** 版    本:V1.0
** 創 建 人:Byron
** 創建日期:2020/3/31 18:57:50
** 修改記錄:
日期        版本      修改人    修改內容   
*****************************************************/
using System.Collections.Generic;

namespace ConsoleApp2.Card
{
    internal class CardContext
    {
        private static Dictionary<CardTypeEnum, ICard> CardDictionary = new Dictionary<CardTypeEnum, ICard>();

        public void AxisMoveAbs(CardTypeEnum Card, int axisNum, double pos)
        {
            CardDictionary[Card].AxisMoveAbs(axisNum, pos);
        }

        public bool GetInput(CardTypeEnum Card, int Ioindex)
        {
            return CardDictionary[Card].GetInput(Ioindex);
        }

        public void InitCard(CardTypeEnum Card)
        {
            CardDictionary[Card].InitCard();
        }

        //初始化容器
        public void InitContext(List<CardTypeEnum> CardList)
        {
            foreach (CardTypeEnum item in CardList)//註冊
            {
                switch (item)
                {
                    case CardTypeEnum.NULL:
                        break;
                    case CardTypeEnum.臺達:
                        break;
                    case CardTypeEnum.研華:
                        CardDictionary.Add(CardTypeEnum.研華, new 研華Card());
                        break;
                    case CardTypeEnum.雷賽:
                        CardDictionary.Add(CardTypeEnum.雷賽, new 雷賽Card());
                        break;
                    case CardTypeEnum.衆爲興:
                        CardDictionary.Add(CardTypeEnum.衆爲興, new 衆爲興Card());
                        break;
                    case CardTypeEnum.ByronCard:
                        break;
                    default:
                        break;
                }
            }

        }

    }
}

實驗

using ConsoleApp2.Card;
using System.Collections.Generic;

namespace ConsoleApp2
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            ////原始模式實驗
            AxisCard axisCard = new AxisCard();
            axisCard.InitCard(CardTypeEnum.研華);
            axisCard.AxisMoveAbs(1, 1000);
            axisCard.GetInput(7);

            CardContext cardContext = new CardContext();
            cardContext.InitContext(new List<CardTypeEnum>() { CardTypeEnum.研華 });
            cardContext.InitCard(CardTypeEnum.研華);
            cardContext.AxisMoveAbs(CardTypeEnum.研華, 1, 1000);
            cardContext.GetInput(CardTypeEnum.研華, 7);
        }
    }
}

結果

在這裏插入圖片描述

總結

寫到這裏,好處應該是已經可以看到非常明白了,原始模式的AxisCard的這個類會隨着兼容卡的增加越來越多,只要有一粒老鼠,這個類在後期兼容十幾種卡的時候隨時都有可能爆炸。
上面的例子是卡,同樣大多數的控制硬件都可以用這種方式實現,達到解耦的目的,例如鐳射測高,歐姆龍,基恩士,松下,國產,用一個策略模式都可以輕鬆實現解耦。
實驗的源代碼我會上傳,鏈接https://download.csdn.net/download/bayinglong/12289035
積分5分,不多,覺得寫得可以可以添加關注。
有招聘意向也可聯繫微信18588205776

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章