正在学习的,飘过。。。。 |
本帖最后由 Crazy_GF 于 2014-8-14 14:44 编辑 英文原文:A complete project with Ardu 参与翻译(3人):realZ, LeoXu, Ley 介绍: ———————————————————————————————————— 我有一个上小学的女儿. 作为一位父亲,当然该负起责任. 我喜欢自己作为父亲的角色,对此我毫无疑问. 但因此所带给我的困扰则是无止境的数学学习事务. 有时候这真的让我很头疼. 2+2, 5+6, 4+3,一遍又一遍. 那才刚开始呢, 现在又多了减法: 5-4, 10-4 .. 而每个人都知道这是没有结束可言的. 我抱怨的够多了,因而决定利用此项技术. 你知道的,技术为人而生, 而现在是为我而存在. 到这里来,我亲爱的 Arduino, 我需要你. 在最开始的时候,我希望这个项目能很容易实现. 我预计所有需要做的事情就是写一些函数来展示一些数字,并且为了根据趣味性,也许要来点蜂鸣声和一些LED灯光. 然后,情况在我开始精心考虑它的时候发生了改变, 出现了一些硬件管理问题, 然后是内容管理问题. 我们这个小小的 Arduino 应用程序变成了一个认真把握的东西,这导致我写下了这篇文章. 让我们先从需求开始吧. 计划需求:—————————————————————————————————————————
————————————————————————————————————————— 我们在这个项目中需要什么:
看看下面的硬件设计: 注意一些和上面不匹配的部分:
(我用Arduino UNO开启了这个项目,但是因为内存的需要后来改用Arduino Mega继续这个项目。开始的时候,Arduino UNO工作的很好。但是,当代码量增加,我无法将RAM使用量控制在Arduino UNO的容量之内,然后就想你所想的,我最终启用了Arduino Mega,它有8K的SRAM。) 软件设计: ————————————————————————————————————————— 图1:设计的概览 系统被分为2个主要部分。就像你在图1中看到的,第一个模块负责硬件的管理。
表现层负责与用户的交互。它包含图形界面的处理(菜单和页面)并包含管理子系统。
简单的类框图如下。这些图像展示了基本的框架,帮助你更容易的理解实际的类实现。 硬件管理:————————————————————————————————————————— MFK_InputDevice将Keypad2和AdKeyboard统一为同一个接口。它处理它们的事件,并向其客户端提供一组新的编码,如下所示。 图2:输入子系统 按键映射:
MFK_OutputDevice继承自SerialLCD类。它结合SerialLCD类的功能,并对其进行了增强。 图3:输出子系统 一个信号模式从信号源产生。一个模式连同它的索引被储存在信号控制器中。想要启动一个信号模式非常简单,只要用它的索引从信号控制器调用它。 图4:发信系统 在硬件管理层顶层的是MFK_Hardware类。它只会所有其他硬件设备,对客户端隐藏多余的复杂性。举例来说,PIRMotionandSignalController没有被暴露给客户端。但是输入和输出设备必须要向外界开放,因为UI系统需要对这些功能的直接访问。信号模式也是在这个类里构建的,可以通过索引来访问他们。 图5:硬件管理 表现层:————————————————————————————————————————— 这一层负责与用户进行交互,它提供了视觉元素和内容。 ContentFactory根据toContentTypeEnum和ContentLevelEnum创建ContentProviders。客户端得到ContentFactory的实例,之后他可以请求一个content provider。 图6:内容管理 VisualItem是所有的视觉元素(菜单和页面)的基类。它还将硬件管理和呈现结合起来。'show' 和'msgbox'方法通过调用和回调VisualItem提供的方法使用输出设备(MFK_OutputDevice)和输入设备(MFK_InputDevice) 。'msgbox'方法也有能力启动一个信号模式,只要调用硬件(MFK_Hardware)的'signal'方法就可以了。 菜单就像他的名字一样,提供了一系列的菜单项可以选择。用户可以通过一个菜单项前面的索引选择它,然后菜单 'show' VisualItem。 Pageis是显示内容的视觉工具。除了娱乐内容,它会等待用户的输入。用户'Enter'她的答案,显示信息告知她对错。显示信息之后,就需要从内容管理获取新的内容。 Chapter是ContentProvider和Page之间的中间类。当一个页面被第一次显示时,与其相关的chapter和ContentProvider就会被创建。用户的答案直接由chapter处理,并由chapter判断其对错。Chapter也对页面内的学习会话进行统计。FunChapter是一种不向用户要求答案的chapter,QuizChapter是限时的chapter。在一个quiz chapter中,问题只有在时间截止之前才能回答。 图7:UI管理 实现:————————————————————————————————————————— 我希望你已经清楚了系统的通用结构。现在,是时候深入到代码中去,那里是真正的乐趣开始的地方。 我想以MathForKid.ino开始。它是上传到Arduino主板上的主要代码。
就这么多。在Arduino上运行你的应用吧。好吧,也许解释一下会更好。 正如我在“软件设计”那部分开头所说的,我们有两个部分:一个用来硬件管理,另一个用来展示。它们在代码顶部定义为全局变量,我们在 'setup'函数中将它们初始化。'loop'函数调用代码来更新它们。 事实上,CreateUI方法也是在这个文件中实现的。当用户开始交互时,它创建用户接口。mainMenu、所有的子菜单和一切页面都是这个方法产生的,chapter的属性也是其赋予的。
我们接着来看这个应用的设计模式。 就像你所想的,MFK_Hardware是Facade模式的一个例子。它将底层的硬件管理问题隐藏起来,并对客户端提供了干净的接口。它同时也是 Singleton模式的代表,因为整个系统运行时其只产生一个实例。为了实现这个功能,MFK_Hardware的构造器、复制和赋值操作都被声明为私有方法。
你只能通过getInstance静态方法访问它们,这个方法是公共的:
MFK_InputDevice也是Facade模式的一个好例子。它将两个不同的输入设备(矩阵键盘和模拟键盘)映射为同一个设备。不止这样,它还具有Observer模式的特征。它是MFK_InputDeviceClient类型的ClientOwner,客户端可以在MFK_InputDeviceClient中注册/注销其对MFK_InputDevice的监听。这样,当状态变化的时候(在这里就是按键被按下),所有的客户端都会被告知。我在这个项目的很多地方都使用了这个模式。
ClientOwner实现了register/unregister功能。一个MFK_InputDeviceClient重载invokeMFKInputCallback回调方法并将其自己注册到ClientOwner。之后MFK_InputDevice可以通过它提供的回调方法告知它状态的变化。VisualItem继承了MFK_InputDeviceClient,因此一个visual item可以将自己注册到MFK_InputDevice并监听输入。 ContentFactory类和ContentProvider类也有一些有趣的属性。ContentFactory是一个Singleton,它也有Factory模式的特征。它为客户端产生内容。但ContentProvider的输出依赖于客户端的请求。
ContentProvider类和Capter类可以被当做Strategy模式的一个例子。一个content provider在一个chapter环境下运行。ContentProvider通过为不同实例准备的算法提供信息(在这里就是问题和答案)。
————————————————————————————————————————— 你懂的,开发应用不只是敲代码。好的需求带来好的设计,好的设计带来好的软件。什么是好?这在很多软件工程的书中都有回答(这不是本文的主题)。为了更好地开发软件,我们需要知道设计模式。(顺便问一句,这段中一共出现了多少个好呢?) 设计模式,像它的名字一样,概括了一类问题的解决方案。因此,不要再造轮子了,为了更好的工作,我们需要有关设计模式的基础知识。 但是,将设计模式应用到一个问题上比看起来的要难。你不能让问题去适应模式,如果你改变原有问题那只会让你的软件变得更糟。我所做的,就是对模式进行修改,让它适应我的需求。如果当前问题不需要一种结构,我不会为未来的预期设想对结构做任何改动。你可能会觉得这很显然,但是我已经见过很多项目就是因为这个原因延期了。在软件开发中,时间代表金钱,时间就等于金钱。你做多余的事情就意味着金钱的损失,对你和客户都一样。 我会继续研究这个项目。我知道一些部分可以做的更好,如果你有任何建议我非常欢迎。(娱乐环节还没有做,不是flash library就是我代码中的调用有问题,所以我没能完成它) 参考资料:————————————————————————————————————————— ————————————————————————————————————————— 这是一个进行中的项目。源代码在文章发布后有所改动,你可以在https://github.com/ozanoner/arduino下载到最新的版本。 本文转载自:开源中国社区 |