像这样连锁调用,如何设计数据流向

cs1438250 2016-03-23 10:22:30
有n组连续的数据a1 a2 ....b1 b2....等等

类A 类B 类C

先把数据放入A1中,经过运算,得到的结果放入类B中的,类B中对一系列数据处理后得到最终结果,反馈到界面类C显示出来。

类A 会有很多个实例,类B的实例关联类A也会有很多个。类C只有一个实例。

该如何写好?

这样写可以不可以。

A的代码中new 一个B的实例,再new一个A的实例,就创建了关联的B的实例,通过set往A的实例中传值,set一次算一次结果,调用B的实例的set传入值。 但最终B的实例的结果是先返回给A的实例,还是直接用C的实例去get。C的实例能不能直接get B的最终结果?

...全文
402 37 打赏 收藏 转发到动态 举报
写回复
用AI写文章
37 条回复
切换为时间正序
请发表友善的回复…
发表回复
software_artisan 2016-03-26
  • 打赏
  • 举报
回复
不就是采集->加工->显示么?不明白楼主在纠结什么? 数据是什么?数据只是原材料而已,你想怎么加工就怎么加工就是了,想要怎么流转就怎么流转就是了。这有什么可纠结的呢? 根据我的理解,楼主的你系统不过是不断地采集数据、进行条件滤波、刷新显示。这个跟有几个实例有个毛关系?莫非你是采集一次数据就new一个对象?
wanghui0380 2016-03-26
  • 打赏
  • 举报
回复
至于我上面提到滴RX下eventbus实现,因为net程序员大多数还在沉迷于传统的技术,所以没有资料给你(我自己的项目因为是公司代码,我就不贴了) 我们看看java们怎么用那个Rx做eventbus滴 http://www.jianshu.com/p/ca090f6e2fe2 是时候向前看了,微软下次升级变动会相当的大,估计有1/3滴net程序员会不习惯滴(下次升级已经有点破坏性了,名字都改为core 1.0 而不是5.x,6.x了)
wanghui0380 2016-03-26
  • 打赏
  • 举报
回复
引用 35 楼 xuanbg 的回复:
不就是采集->加工->显示么?不明白楼主在纠结什么? 数据是什么?数据只是原材料而已,你想怎么加工就怎么加工就是了,想要怎么流转就怎么流转就是了。这有什么可纠结的呢? 根据我的理解,楼主的你系统不过是不断地采集数据、进行条件滤波、刷新显示。这个跟有几个实例有个毛关系?莫非你是采集一次数据就new一个对象?
你误会楼主了,楼主只是想解耦,比如 设备对象(设备A实例,设备B实例),数据处理算法(平均移动线,中值滤波),至于显示其实我个人不在乎(MVVM足够了) 他想 任意挂接这两个对象, 比如设备A采集数据具备同时挂同时n个处理块的能力(如挂接2次平均移动,3次平均移动算法等) 其实把这块东西微软已经写的好好滴了,我前面之所以提示可以参考IQueryable就是这个原因,为啥IQueryable可以采用链式调用呢??包括我后面提到滴Rx库,TPL dataflow 无一不是链式方法。函数式,声明式早就已经是net滴最基本的手段了,还是我N年前说过滴,一个都不能少!对象也不通神,该用函数式的时候我们照样用! ps:我下面给3个参考连接,都是老外们采用Rx方式,计算平均移动线的例子(包括java的例子,java也有Rx库。甚至js都Rx库) http://stackoverflow.com/questions/14805392/rx-stateful-transform-of-sequence-e-g-exponential-moving-average http://stackoverflow.com/questions/20811745/how-to-calculate-moving-average-in-rxjava https://alexfeinberg.wordpress.com/2014/01/16/rx-moving-average/ 虽然例子本身都是在一个对象里处理,但是有啥关系呢? 分成多个对象实例,也毫不违和,设备A实体产生数据队列,算法B订阅数据队列,甚至可以多个算法顺序挂接(比如先去掉最大数,最小数,在挂接计算平均值)或者并行挂接(同时并行计算3点平均和5点平均),而挂接的方式你也看到了就是链式方法
weishaolin13x 2016-03-25
  • 打赏
  • 举报
回复
因为A/B是实时的,所以要加到总控台里来, 而C不是实时的,不要加到总控台里来,通过数据耦合的方式,C读缓冲池数据,
weishaolin13x 2016-03-25
  • 打赏
  • 举报
回复
比如举一个例子: 总控台接收采集卡A的数据,然后把数据压入栈(A),当栈满了(多少算满需要根据数据格式来配置),则调用数据B来处理数据, 并清空栈,并将结果写入缓冲池,类C隔一段时间就去读缓冲... 类C与总控台没关系。
weishaolin13x 2016-03-25
  • 打赏
  • 举报
回复
将各个数据处理类的 输入数据、输出数据 的格式都定义好, 然后定义好数据流程,定义好后, 做个总控台,负责调度各个处理类来处理数据.... 多个采集卡,多个通道,得建多线程来处理,要不会互相卡住的,
wanghui0380 2016-03-25
  • 打赏
  • 举报
回复
因为你是串口,我不好模拟,我就模拟一个用鼠标绘图的代码,大体上意思跟你相同,只不过数据产生不是串口而是鼠标移动事件 总体意思就是,根据鼠标移动事件在一副图上绘制一个圆,与传统代码唯一的区别就是采用限流每两次鼠标移动事件才计算1次平均值当作,绘制参数
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reactive.Linq; //这是Rx类,你可以用nuget管理器搜索Reactive Extensions就可以搜索到,大胆使用把这是微软的东西,不是其他人滴提供
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        IDisposable _mouseMoveSubscribe;
        Image _sourceImage;
        Image _tempImage;

        private void Form1_Load(object sender, EventArgs e)
        {
            _sourceImage = Image.FromFile(@"I:\新建文件夹1\000001_20151209_00097051.BMP");
            _tempImage = Image.FromFile(@"I:\新建文件夹1\000001_20151209_00097051.BMP");
            this.pictureBox1.Image = _sourceImage;
            this.WindowState = FormWindowState.Maximized;

            

        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
  
            Point startPoint = e.Location;

            
            //鼠标按下左键开启,rx订阅鼠标事件的可观测流
            _mouseMoveSubscribe =
                Observable.FromEventPattern<MouseEventArgs>(this.pictureBox1, "MouseMove") //将传统事件数据转换成可观察流
                .Buffer(2) //按你的需要缓存鼠标移动数据事件,每两次推送一次
                .Subscribe(x =>
                {
                    MemoryStream ms = new MemoryStream();

                    _tempImage.Save(ms, ImageFormat.Bmp);
                    Image t = Image.FromStream(ms);
                    Graphics graph = Graphics.FromImage(t);

               //上下代码都不用管,那是绘图代码。主要讲这里,因为是2次缓存的数据流,我为了演示你的需要,特地写成求2次鼠标位置的平均算术值
                    var currentPoint = new Point((x.First().EventArgs.X + x.Last().EventArgs.X) / 2, (x.First().EventArgs.Y + x.Last().EventArgs.Y) / 2);
                   // Point currentPoint = new Point(emove.X, emove.Y);
                    graph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;//消除锯齿  
                    // graph.DrawLine(new Pen(Color.Blue, 2), startPoint, currentPoint);

                    Rectangle rect = new Rectangle(2 * currentPoint.X - startPoint.X, 2 * currentPoint.Y - startPoint.Y, 2 * (startPoint.X - currentPoint.X), 2 * (startPoint.Y - currentPoint.Y));
                    graph.DrawEllipse(new Pen(Color.Blue, 2), rect);
                    this.pictureBox1.Image = t;
                }
                );
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
     //松开鼠标,取消订阅鼠标移动事件,并把绘制图像缓存一下,以便下次在次基础上绘制。
            if (_mouseMoveSubscribe != null)
            {
                _tempImage = this.pictureBox1.Image;
                _mouseMoveSubscribe.Dispose();
            }
        }

    }
}
weishaolin13x 2016-03-25
  • 打赏
  • 举报
回复
类是关联的,但是数据是平行的。 ----------------------------------------------------- 你这是控制耦合,很不好的设计,你可以改成数据耦合,就是类之间没有关系,而是数据建关系, 各个类相互独立,类只定义输入数据格式标准,输出数据格式标准, 然后定义数据格式,定义数据流程,定义采集原始数据的格式/频率/样本/
wanghui0380 2016-03-25
  • 打赏
  • 举报
回复
上面说的Rx和总线方式设计 下面说一说TPL dataflow, 如果这个相对就更简单些,你串口出来的source块,我在source块上挂接bufferBlock 可以把?然后继续挂接TransfromBlock处理转换块也没问题把
xuzuning 2016-03-25
  • 打赏
  • 举报
回复
那你的 A 和 B 不都有了吗? 维持现状就可以 C 是显示,用个定时器控制一下不就行了吗
wanghui0380 2016-03-25
  • 打赏
  • 举报
回复
像你说的那些东西,其实很类没啥关系 那些东西在我们口中跟类没有关联,我们口中说的是“数据管道”,“限流”,“时间窗口” 比如rx下,我们可以通过 Observale.Interval(Timespan.FromSeconds(2)) //为了演示我每隔2秒产生一个数据,在你那里数据产生当然是串口通讯 .Buffer(2) //数量限流,每收到2个数据,我才对外发出去,否则就缓存的自己这里 .Subscirbe(x=>{订阅上面发出的数据,上面肯定就是4秒的2个数据发给我了}) 如果在配合TPL dataflow做一下管道挂接,你这东西很容易实现的 至于你多个实体类其实,设计上我们也通常解耦了,我们使用eventbus(行为总线),每个类直管向总线发送信息,总线说只要有人订阅这个类型的信息我就推送给他,否则不做处理。 比如你的串口A数据接收实体,交给总线一个标记为“数据A采集”的数据,而总线根据你的限流规则(如果设计的好,自然这里可以随意注入限流规则)去分发信息,然后我一个叫串口A数据解析class的订阅的这条消息,自然他会接收到这条消息,并把处理后的数据发给总线,同样总线会查一下有没有人定义这个“串口A数据解析结果”,如果没有人订阅,ok,流程结束
wanghui0380 2016-03-25
  • 打赏
  • 举报
回复
你可以百(谷)度(歌)“TPL dataflow rx 限流”
cs1438250 2016-03-25
  • 打赏
  • 举报
回复
引用 24 楼 xuzuning 的回复:
类是关联的,但是数据是平行的。??? 类是独立的,但是数据是串行的。 没有前期的加工,就没有后期的数据 不过这样的确不行 data1 = A.Process(data); data2 = B.Process(data1); C.Show(Data2); 要 while(loot) { A.Process(data); B.Process(data); C.Show(data); } 显然,因为不同的节奏, B.Process(data); 和 C.Show(data); 在大部分时间是直接返回,不做任何处理的 你会说每个方法需要不同格式的数据 但这不妨碍 data 中容纳有不同的数据集(甚至包含控制指令) 当然你也可以通过一个控制器去分别触发 A、B、C 我认为侦听 data、data1、data2 的规模后去触发相应动作会很麻烦,也不利于系统的扩展
有一个底层的线程循环采集数据,把数据填入A的data中,当A的data达到要求的规模(比如10个20个)之后,触发B的处理,B的处理结果出来后,要作为参数实时判断控制其他设备,C类的显示只是随机取一次结果给人参考的。
xuzuning 2016-03-25
  • 打赏
  • 举报
回复
类是关联的,但是数据是平行的。??? 类是独立的,但是数据是串行的。 没有前期的加工,就没有后期的数据 不过这样的确不行 data1 = A.Process(data); data2 = B.Process(data1); C.Show(Data2); 要 while(loot) { A.Process(data); B.Process(data); C.Show(data); } 显然,因为不同的节奏, B.Process(data); 和 C.Show(data); 在大部分时间是直接返回,不做任何处理的 你会说每个方法需要不同格式的数据 但这不妨碍 data 中容纳有不同的数据集(甚至包含控制指令) 当然你也可以通过一个控制器去分别触发 A、B、C 我认为侦听 data、data1、data2 的规模后去触发相应动作会很麻烦,也不利于系统的扩展
  • 打赏
  • 举报
回复
设计活动流程图(以及时序图、状态图,等等),这样一个人就知道该如何设计软件了。因为它们的规范都是研究多个实体之间的来回、反复交换数据机制。 如果一个人空洞到连这些都不设计,那么他就会以为数据自己能把自己当作操作实体,明明是“数据库把数据保存起来”而他偏偏要说是数据自己把自己保存到磁盘上,明明是各种操作机制加工数据而他偏偏以为是只要有静态数据概念就够了。这样的思维方式,除了写点 sql 语句以外,能设计什么实用的应用呢?
cs1438250 2016-03-25
  • 打赏
  • 举报
回复
引用 19 楼 sp1234 的回复:
看看你的纠结的内容吧,反复纠结名词儿(class命名),而纠结的结果是说背后的各种操作不好控制。 如果只能看到一些静态名词儿,而一旦设计动态的流程你就混乱了,这说明你前边的名词儿也是无用的。你应该把重点放到画出一个流程图上来,而不是纠结名词儿。 比如说这样一个流程,一个手机产生了image,然后把它送到互联网上的一个服务,这个服务识别了其中的“信用卡号”然后通知了卡主。按照你的理解,你纠结于image类型要不要给信用卡对象set什么东西,这简直就是瞎设计了。之所以产生这种混乱,就是你夸大了静态模型的作用。静态概念在初始设计中顶多占15%的分量,你还要深入一步去画出流程图,才能刚刚好开始进行设计。
已经做了很多项目了,感觉代码混在一起很混乱,所以想分层次设计,复用性强一些。
  • 打赏
  • 举报
回复
引用 18 楼 cs1438250 的回复:
传感器类型太多,有的是pci通道采集,速度可以很高,有的是串口,速度很低。处理方法也不同,有平值,滑动均值等等算法。
概念可能有什么附属的东西(以及概念是否足够),不是你空洞地写什么抽象的理论就能放之四海而皆准的。你必须写出多个流程图来,先说清楚了动态的东西,才能确定最终的class。 比如说,传感器class跟(传感器所处理的)数据class,有的人连这个都分不清楚,硬要把传感器的接口定义到数据上,这是什么原因?空洞呗!
  • 打赏
  • 举报
回复
看看你的纠结的内容吧,反复纠结名词儿(class命名),而纠结的结果是说背后的各种操作不好控制。 如果只能看到一些静态名词儿,而一旦设计动态的流程你就混乱了,这说明你前边的名词儿也是无用的。你应该把重点放到画出一个流程图上来,而不是纠结名词儿。 比如说这样一个流程,一个手机产生了image,然后把它送到互联网上的一个服务,这个服务识别了其中的“信用卡号”然后通知了卡主。按照你的理解,你纠结于image类型要不要给信用卡对象set什么东西,这简直就是瞎设计了。之所以产生这种混乱,就是你夸大了静态模型的作用。静态概念在初始设计中顶多占15%的分量,你还要深入一步去画出流程图,才能刚刚好开始进行设计。
cs1438250 2016-03-25
  • 打赏
  • 举报
回复
引用 17 楼 sp1234 的回复:
[quote=引用 15 楼 cs1438250 的回复:]类是关联的,但是数据是平行的。 假如 采集到10个数据放入一个list,经过a类处理得到10个电压值,在经过b类处理得到一个滤波值。 但是c类显示的数值不是把b类处理得到的每个滤波值都显示出来。 因为采集处理速度可能每秒1k 10k 100k。而显示刷新,半秒一次,人的反应也到极限了,太快没有意义。 所以是类级联,数据平行。随机抽取一段供给下一级类处理。
纠结那么多 class 目的是什么呢?为什么不可以在同一个 class 中不同 method 来表示各种计算?到底你的class是干什么用的呢?[/quote] 想想也可以,写一个超大的类,都包括进去。
cs1438250 2016-03-25
  • 打赏
  • 举报
回复
引用 17 楼 sp1234 的回复:
[quote=引用 15 楼 cs1438250 的回复:]类是关联的,但是数据是平行的。 假如 采集到10个数据放入一个list,经过a类处理得到10个电压值,在经过b类处理得到一个滤波值。 但是c类显示的数值不是把b类处理得到的每个滤波值都显示出来。 因为采集处理速度可能每秒1k 10k 100k。而显示刷新,半秒一次,人的反应也到极限了,太快没有意义。 所以是类级联,数据平行。随机抽取一段供给下一级类处理。
纠结那么多 class 目的是什么呢?为什么不可以在同一个 class 中不同 method 来表示各种计算?到底你的class是干什么用的呢?[/quote] 传感器类型太多,有的是pci通道采集,速度可以很高,有的是串口,速度很低。处理方法也不同,有平值,滑动均值等等算法。
加载更多回复(17)

110,526

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧