前言

POS从16年底开始设计到现在都过去快两年了,这里我做一个简单的回顾。

技术选型

NativeUI:性能最高,开发难度最大,代表产品QQ和微信,没有基因没有技术栈。

Electron+H5:不支持xp,使用xp的电脑在影城中还存在50%以上,只能否决。

NWJS+H5:总体上比Electron差一些,但是支持xp,因为存在性能,操作体验,安装包庞大等问题,被钉钉弃用。

NativeUI+CEF+H5:hybird框架,将性能要求高的UI用C++写,变化频繁的用h5写,钉钉客户端最新采用的技术框架。网易云音乐客户端也是类似框架。也没有技术栈。

WinForm:.Net平台下的两大UI框架之一,具有开发简单,轻量,性能高等优点,但是有自定义UI难度高,微软停止更新等缺点。

WPF:.Net平台下的两大UI框架之一,具有现代化的UI界面和比较先进的MVVM编程思想。公司上代产品使用的技术,具有广泛的实践经验,读卡和打印等类库可以直接继承使用。这是最不容易采坑的技术方案。

当时公司的战略是用迅雷不及掩耳之势打下云售票这片新市场,一边要和时间赛跑,一边要保证产品质量和功能,需要开发节奏要快,狠,准,所以综上所述,最终沿用WPF技术开发新产品。

一个优秀系统架构应该是具有高可扩展性、高内聚、低耦合等特点,在经历了各版本的变更之后依然保持着清晰、灵活、稳定的系统架构。而模块化是其中一个解决方案,为了以后框架的灵活扩展和应付日益复杂的业务,模块化应该是新产品的设计方向。

业务模块

POS是给前台售票员使用的系统,业务上相对简单,大部分都是与顾客相关,可粗略分为影票,卖品,会员三大类,还有打印,读卡等硬件交互模块,另外还有登录,客屏这些功能,抽钞,赠券等归类为其他业务。

业务模块再细化,系统架构图雏形

上面粗粒度的业务分类还是难以支持系统设计,还是需要进一步的细化。在系统架构层面就是要业务模块在细化,和补全必要的组件,例如日志,数据服务等。

完全解耦的平台化

最开始想的方案是完全平台化,整个系统的核心只是作为启动器的exe,其他模块dll作为插件都可以替换的,再通过读取到内存,以反射方式加载,可以实现各个模块的热插拔。启动器和插件的关系就好像浏览器和H5页面。

这个方案可以使各个模块完全解耦,从编译的角度来说完全独立。但缺点很明显,代码冗余大,日志,打印等功能基本都一样的,修改和维护相当困难。另外各模块之间的业务都是有依赖和关联的,他们之间的通信可以采用字符串传递,再反序列得到实例。事实上这种靠口头约定的通信方式出现一丁点的误差就会造成严重的后果。综上,这种方案并不适合POS。不过可以作为一个局部平台,对外接收各种第三方开发的插件实现业务功能。

改进方案

上面灾难性的字符串通信改成各模块引用dll,实现强类型通信。作为一个UI系统需要用到各个控件,也需要做一个通用类库给各模块引用。另外,为了国际化的需要和主题更换的实现,文案资源和样式也需要独立出来。

具体实现

具体到代码实现层面,考虑到安装包的大小和第三方框架的兼容性,我决定以轻量化作为设计抉择的方向

IOC容器

上面有各式各样模块为了方便管理各个组件,Bootstrapper需要作为一个容器,担任加载和管理组件。

微软集成在.Net 4.0框架中,不需要引入第三方框架,符合客户端轻量化的要求。

可根据路径扫描和加载组件。

可以卸载和重新组合组件。

以MEF框架为基础,我做了几样工作。

定义了CataLog.xml配置文件,里面记录着每个组件的实际文件路径,在程序启动时,读取配置加载需要的组件。

设计IModule接口,如果组件需要在运行时执行任务,可以实现接口的Initialize方法。

封装MEF的容器为全局容器Global.Container,可通过容器导出其他组件的服务。

改进MEF的加载组件的方式,先把组件读取到内存的方式,再转化成Assembly加载,可以实现运行时卸载组件,更新组件。

MVVM框架

MVVM是Model-View-ViewModel的简写,是一种比较先进的设计模式,WPF本身就是一个实现MVVM模式的框架,主张数据驱动理念,但是它里面对命令,属性通知等概念的实现不是很友好,所以我找了行业上比较成熟的第三方框架做了一番对比。

MvvmLight, 是一个轻量级的MVVM框架,比较适合小程序开发,对命令,属性通知接口等有相应的实现,使用Mesage类作为消息传递。使用SimpleIoc容器。

Prism,相对于来庞然大物,适合大规模程序开发,支持模块化,组合UI,组合命令,事件聚集,支持Unity和MEF作为IOC容器。使用上非常复杂,而实际开发上很少用得上全部功能。

最后,走读MvvmLight和Prism文档和源码,取两者之长构建自己的框架。参考MvvmLight将命令,属性通知等功能在Infrastructure中实现,参考Prism的模块化思想,以接口IMdoule作为模块间加载和交互的桥梁。

控件库

为了风格统一和代码复用,需要一个控件库来开发。但是原生控件样式简陋功能少,而第三方控件比较好有ModernUI,Xceed和Telerik,前者开源,扁平化风格,功能上和原生差不多,后两者部分开源,高度封装,功能强大,不过要收费。实际上,按照视觉搞,原生和第三方控件都是不符合要求,最终还是要自建LarkUI控件库,重写样式和功能以满足视觉和交互的要求,最终集成在Infrastructure。

自动更新

新产品的迭代是非常频繁的,为了防止版本碎片化,POS需要实现强制更新,另外频繁的更新会降低用户体验,所以必须要自动更新且尽量无感,启动时检查,下载更新包替换文件后重启。

小结

本文简单介绍了POS的架构,总的来说,在行业上WPF框架并没有一个标准的解决方案,所以整个设计上有比较强烈的个人喜好在里面。未来的话,也可以抽象出来作为一个WPF的标准客户端架构输出到行业去。

【WPF】影城POS的前世今生的更多相关文章

  1. WPF 基础到企业应用系列2——WPF前世今生

    1.开篇前言       非常多时候了解一项新技术的历史和趋势往往比这项技术的本身价值还要重要.WPF作为一项新技术(已经三年多了.或者应该叫老技术了).我们都有必要了解它的来龙去脉,尤其是公司的CT ...

  2. 重复造轮子系列——基于FastReport设计打印模板实现桌面端WPF套打和商超POS高度自适应小票打印

    重复造轮子系列——基于FastReport设计打印模板实现桌面端WPF套打和商超POS高度自适应小票打印 一.引言 桌面端系统经常需要对接各种硬件设备,比如扫描器.读卡器.打印机等. 这里介绍下桌面端 ...

  3. 第五篇:在SOUI中使用XML布局属性指引(pos, offset, pos2type)

    窗口布局的概念 每一个UI都是由大量的界面元素构成的,在Windows编程,这些界面元素的最小单位通常称之为控件. 布局就是这些控件在主界面上的大小及相对位置. 传统的布局一般使用一个4个绝对坐标来定 ...

  4. WPF基础到企业应用系列6——布局全接触

    本文转自:http://knightswarrior.blog.51cto.com/1792698/365351 一. 摘要 首先很高兴这个系列能得到大家的关注和支持,这段时间一直在研究Windows ...

  5. WPF拖放功能实现zz

    写在前面:本文为即兴而作,因此难免有疏漏和词不达意的地方.在这里,非常期望您提供评论,分享您的想法和建议. 这是一篇介绍如何在WPF中实现拖放功能的短文. 首先要读者清楚的一件事情是:拖放主要分为拖放 ...

  6. 在uwp仿制WPF的Window

    移植WPF软件到uwp时碰到用作对话框的Window有多种处理选择.我个人认为最省事的是用ContentDialog模拟Window. 比如你想把上面这个WPF窗体弄到uwp里面去 1.修改Conte ...

  7. 【转】【WPF】wpf 图片指针处理

    我一直用GDI+做Winform 的基于指针的图片处理,这次下决心全部移到wpf上(主要是显示布局很方便)采用的图片是2512*3307 的大图 830万像素类库基于WritableBitmapEx ...

  8. WPF 基础到企业应用系列索引

    转自:http://www.cnblogs.com/zenghongliang/archive/2010/07/09/1774141.html WPF 基础到企业应用系列索引 WPF 基础到企业应用系 ...

  9. WPF拖动总结[转载]

    WPF拖动总结   这篇博文总结下WPF中的拖动,文章内容主要包括: 1.拖动窗口 2.拖动控件 Using Visual Studio 2.1thumb控件 2.2Drag.Drop(不连续,没有中 ...

随机推荐

  1. sgu 101 Domino 解题报告及测试数据

    101. Domino time limit per test: 0.25 sec. memory limit per test: 4096 KB 题解: 求多米诺骨牌按照一定方式放置能否使相邻的位置 ...

  2. wait、notify为什么要放在同步代码块中

    等待方遵循的原则: 获取对象的锁,不满足条件就调用wait()方法,条件满足继续执行 通知方原则: 获取对象的锁,改变条件,然后notify 每个对象都有一个监视器锁,这个监视器锁的数据结构如下: w ...

  3. 前端使用canvas绘制立体三角形

    前端绘制立体效果的三角形的demo 在移动端使用时,需要自适应屏幕.canvas上无法设置rem,所以在canvas外加一个父级元素设置为rem,再将canvas的宽高设置为100% 100%. 如果 ...

  4. 20145312 《Java程序设计》第五周学习总结

    20145312 <Java程序设计>第五周学习总结 学习笔记 Chapter8 异常处理 8.1语法与继承架构 1.Java中的错误以对象方式呈现,只要捕捉包装错误的对象,就可以针对该错 ...

  5. [BZOJ1058]报表统计

    Description 小Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工 作,作为她的生日礼物之一.经过仔细观察,小Q发现统计一张报表实际上是维护一个 ...

  6. java基础笔试题二(集合关系)

    知识点:java集合继承关系(Collection,Map) 1.集合框架体系图 2.java的集合层次 来自博客(http://blog.csdn.net/stubbornaccepted/arti ...

  7. docker 修改 mysql 5.7 sql_mode

    docker exec -ti {容器ID} /bin/bash   进入容器 apt-get install vim 安装vim 找到 vim /etc/mysql/my.cnf 在 [mysqld ...

  8. UVA 1393 Highways(数学思想)

    题意:给你n.m(n,m<=200),问你有多少条非水平.非垂直的直线有多少条经过至少两个点 题解:我们需要枚举的是只画一条线的矩形,对于大小a*b的矩形必须保证gcd(a,b)=1才能不重复 ...

  9. L1-3 宇宙无敌加法器 - 令人激动的一道题目

    L1-3 宇宙无敌加法器 - 令人激动的一道题目 感觉好久没有这么认真的做一道题了,今天看到一句话, 说是编程是一个工程型的工作,想要学好,"无他,唯手熟尔" 之前觉得自己笨,怀疑 ...

  10. Java实习一

    简单的二元一次方程求解 import java.lang.Math; import java.util.Scanner; public class Solve{ public static void ...