程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> [原]實例-簡單設計&精簡代碼&復用代碼,實例設計

[原]實例-簡單設計&精簡代碼&復用代碼,實例設計

編輯:C#入門知識

[原]實例-簡單設計&精簡代碼&復用代碼,實例設計


引言

本文以實際項目為例談一談我個人對於軟件開發的理解,偏細節   軟件項目B 基於.net平台,使用WPF框架,c#語言,MVVM模式開發的桌面軟件 該軟件支持可視化的設計器功能,允許所見即所得的方式為頁面添加文字、圖像等元素。可對元素進行編譯解析,生成對應的二進制數據下發至下位機,本文不對軟件整體設計做介紹,僅列舉部分設計及編碼細節進行介紹  

獨立的Model層數據類型

Model層作為獨立的數據訪問層,數據類型定義保持獨立,僅記錄數據本身,ui無關 結構如下圖 BGProject 項目類型,組合多個BGDiargam視圖對象 BGDiagram視圖類型,組合多個BGElement元素對象,存在多個派生元素類型   View層在使用數據時,可封裝視圖數據類型組合Model數據類型,以記錄其他UI相關數據  

適度封裝以簡化代碼

編譯過程需對文字、圖片等做不同處理 初期實現時僅實現了一個TextCompiler,後續陸續實現ImageCompiler等,遂提取抽象基類CompilerBase 形成如下結構   Compile方法由各個派生類自行實現編譯邏輯 上層編譯邏輯的實現,簡單使用多態,如下
    public bool Compile(BGProject project, out String errorMessage)
    {
        TextCompiler textCompiler = new TextCompiler(project);
        ImageCompiler imageCompiler = new ImageCompiler(project);
        XxxCompiler xxxCompiler = new XxxCompiler(project);

        foreach (CompilerBase compiler in
            new CompilerBase[] {textCompiler, imageCompiler, XxxCompiler})
        {
            compiler.Compile();
            if (!compiler.Validate(out errorMessage))
            {
                return false;
            }
        }
        
        // ...
    }

 

Don't Repeat Yourself 復用代碼

每一種數據的編譯邏輯中,都需要遍歷相應類型的元素,因此考慮將元素遍歷邏輯獨立出來 為基類TravelCompilerBase添加如下方法
        protected static void TravelElements<T>(BGProject project, BGElementType elementType, Action<T> action)
            where T : BGElement
        {
            foreach (BGDiagram diagram in project.Diagrams)
            {
                foreach (T element in
                    diagram.Elements.Where(e => e.ElementType == elementType))
                {
                    action(element);
                }
            }
        }
處理邏輯通過action參數傳遞進來   TextCompiler中編譯文字元素時,調用上述方法,通過lambda表達式生成匿名方法完成處理邏輯
            TravelElements<BGTextElement>(Project, BGElementType.Text,
                                          element =>
                                              {
                                                  //.... 針對目標元素做相應處理
                                              });

處理該特定問題,這裡使用委托的方式,泛型化使其易於使用,你也可以使用TemplateMethod模式

 

合宜地使用靜態類型封裝基本工具類型

靜態類型是一種良好組織獨立工具method的方式 許多不專業的程序員常將靜態類型作為存儲全局對象的容器,這其實是在破壞軟件結構。應盡一切可能避免使用靜態類型變量。  

序列化工具類

項目中涉及數據序列化到本地文件,直接使用如下工具類型

    public static class SerializeUtility
    {
        public static void BinarySave<T>(String filePath, T obj)
        {
            using (Stream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(stream, obj);
            }
        }

        public static T BinaryLoad<T>(String filePath)
        {
            return BinaryLoad<T>(filePath, null);
        }

        public static T BinaryLoad<T>(String filePath, SerializationBinder serializationBinder)
        {
            if (!File.Exists(filePath))
            {
                return default(T);
            }

            using (Stream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None))
            {
                IFormatter formatter = new BinaryFormatter();
                if (serializationBinder != null)
                {
                    formatter.Binder = serializationBinder;
                }
                return (T)formatter.Deserialize(stream);
            }
        }
    }

int與byte數組轉換工具類

涉及到傳輸數據至下位機,考慮數據存儲格式,編寫如下工具類,支持littleEnding與bigEnding

    // Created by Ant 2014-4-30
    public static class BytesConverterUtility
    {
        public static byte[] GetBytes(int value, int length, bool isLittleEndian = true)
        {
            if (value < 0)
            {
                throw new ArgumentException("value不能為負數");
            }

            if (length > 4)
            {
                throw new ArgumentException("length不能>4");
            }

            var rawBytes = BitConverter.GetBytes(value);

            if (rawBytes.Length < length)
            {
                throw new ApplicationException(
                    String.Format("BitConverter.GetBytes返回的字符數{0}小於目標字符數{1}", rawBytes.Length, length));
            }

            var bytes = new byte[length];

            if (BitConverter.IsLittleEndian != isLittleEndian)
            {
                Array.Reverse(rawBytes);
                Array.Copy(rawBytes, rawBytes.Length - length,
                           bytes, 0, length);
            }
            else
            {
                Array.Copy(rawBytes, bytes, length);
            }

            return bytes;
        }

        public static int ToInt(byte[] bytes, int offset, int length, bool isLittleEndian = true)
        {
            if (length == 1)
            {
                return bytes[offset];
            }

            var tempBytes = new byte[length];

            Array.Copy(bytes, offset, tempBytes, 0, length);

            if (!isLittleEndian)
            {
                Array.Reverse(tempBytes);
            }

            switch (length)
            {
                case 2:
                    // 特殊處理,轉換為無符號int類型,返回時自動轉換為Int32
                    return BitConverter.ToUInt16(tempBytes, 0);
                case 4:
                    // 注意,這裡將數據轉換為有符號int類型
                    return BitConverter.ToInt32(tempBytes, 0);
                default:
                    throw new ArgumentException("length 長度非標准值");
            }
        }
    }

工具類型的方便之處在於其獨立性,幾乎無外部依賴,不需要考慮對其進行初始化,拿來就可以直接使用

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved