引言

本文以实际项目为例谈一谈我个人对于软件开发的理解,偏细节
 
软件项目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 < )
{
throw new ArgumentException("value不能为负数");
} if (length > )
{
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, , length);
}
else
{
Array.Copy(rawBytes, bytes, length);
} return bytes;
} public static int ToInt(byte[] bytes, int offset, int length, bool isLittleEndian = true)
{
if (length == )
{
return bytes[offset];
} var tempBytes = new byte[length]; Array.Copy(bytes, offset, tempBytes, , length); if (!isLittleEndian)
{
Array.Reverse(tempBytes);
} switch (length)
{
case :
// 特殊处理,转换为无符号int类型,返回时自动转换为Int32
return BitConverter.ToUInt16(tempBytes, );
case :
// 注意,这里将数据转换为有符号int类型
return BitConverter.ToInt32(tempBytes, );
default:
throw new ArgumentException("length 长度非标准值");
}
}
}

工具类型的方便之处在于其独立性,几乎无外部依赖,不需要考虑对其进行初始化,拿来就可以直接使用

[原]实例-简单设计&精简代码&复用代码的更多相关文章

  1. 3.NetDh框架之缓存操作类和二次开发模式简单设计(附源码和示例代码)

    前言 NetDh框架适用于C/S.B/S的服务端框架,可用于项目开发和学习.目前包含以下四个模块 1.数据库操作层封装Dapper,支持多种数据库类型.多库实例,简单强大: 此部分具体说明可参考博客: ...

  2. 通过游戏学python 3.6 第一季 第九章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码--优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁定账号--锁定次数--菜单功能'menufile

      通过游戏学python 3.6 第一季 第九章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码--优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁 ...

  3. 通过游戏学python 3.6 第一季 第八章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码--优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁定账号--锁定次数

    通过游戏学python 3.6 第一季 第八章 实例项目 猜数字游戏--核心代码--猜测次数--随机函数和屏蔽错误代码--优化代码及注释--简单账号密码登陆--账号的注册查询和密码的找回修改--锁定账 ...

  4. C# 求精简用一行代码完成的多项判断 重复赋值

    C# 求精简用一行代码完成的多项判断 重复赋值 哈哈,说实话,个人看着这么长的三元操作也麻烦,但是我也只想到了这样三元判断句中执行方法体能够写到一行,追求的终极目的是,用一行实现这个过程,而且简单,由 ...

  5. python面向对象入门(1):从代码复用开始

    本文从代码复用的角度一步一步演示如何从python普通代码进化到面向对象,并通过代码去解释一些面向对象的理论.所以,本文前面的内容都是非面向对象的语法实现方式,只有在最结尾才给出了面向对象的简单语法介 ...

  6. 函数和代码复用 --Python

    1.关于递归函数的描述,以下选项中正确的是 A.包含一个循环结构 B.函数比较复杂 C.函数内部包含对本函数的再次调用 D.函数名称作为返回值 答案:D 答案解析:递归函数是指函数内部包含对本函数的再 ...

  7. Python-函数和代码复用

    函数的定义与使用 >函数的理解与定义 函数是一段代码的表示 -函数是一段具有特定功能的.可重用的语句组 -函数是一种功能的抽象,一般函数表达特定功能 -两个作用:降低编程难度 和 代码复用 de ...

  8. 6个实例详解如何把if-else代码重构成高质量代码

    本文提纲: 为什么我们写的代码都是if-else?这样的代码有什么缺点?是否有优化的方法?如何重构?异常逻辑处理型重构方法状态处理型重构方法为什么我们写的代码都是if-else?程序员想必都经历过这样 ...

  9. Python学习笔记(五)函数和代码复用

    函数能提高应用的模块性,和代码的重复利用率.在很多高级语言中,都可以使用函数实现多种功能.在之前的学习中,相信你已经知道Python提供了许多内建函数,比如print().同样,你也可以自己创建函数, ...

随机推荐

  1. ZigzagConvert

    public class ZigzagConvert { public static String convert(String s, int nRows) { int len = s.length( ...

  2. Python DB API 连接数据库

    Python DB API Mysql,Oracle,SqlServer 不关闭,会浪费资源.

  3. 云服务器pip下载老失败怎么办?

    pip install -i https://pypi.douban.com/simple django==1.9

  4. Qt5 窗口内的控件随窗口大小自动变化

    http://www.bubuko.com/infodetail-827151.html 讲的很详细

  5. jsp:jstl标签之控制流程

    下面将要讲的用于流程控制的标签,其中包括:if.choose.when 与 otherwise 等.接下来对这些标签逐一讲解. 这个标签的作用和 Java 程序中的 if 语句作用相同,用于判断条件语 ...

  6. c、rust、golang、swift性能比较

    mac 计算速度视觉判断是(由好到差):c > rust > swift > golang 内存开销在mac上是(由好到差):c > rust > golang > ...

  7. linux服务器版svn安装

    1.检查svn是否安装:rpm -aq subversion2.安装命令yum -y install subversion3.建立svn版本库数据存储根目录mkdir -p /application/ ...

  8. LeetCode OJ:Balanced Binary Tree(平衡二叉树)

    Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced binary ...

  9. const、define与sizeof

    一.const的用途 1.定义const常量 2.可以修饰函数的形参,返回值,以及函数体.被const修饰的内容可以受到强制保护,防止被意外修改,提高程序健壮性. const 返回值 函数返回值为 c ...

  10. Bender Problem

    Robot Bender decided to make Fray a birthday present. He drove n nails and numbered them from 1 to n ...