`
sing100star
  • 浏览: 28564 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

用“主线+事件”的方式来编写代码

阅读更多

      业务是主线和事件组合。

      主线是什么?主线就是在完成用户的业务目标时,所涉及到的活动。

      事件是什么?在每一个活动中,相关事物的状态变化。

 

      回顾以前的编程经验,我们关注活动,忽略事件。

      举一个常见的例子来说。小明在购物网站购物,进行支付并成功后,购物网站要做件事: 1 、更新订单状态, 2 、插入支付记录 3 、更新订单日志。 4 、通知支付系统,回调成功。

 

通常的做法如下:

    public void successToPay(PurchaseOrder order,PayResult result){
        //1、更改支付状态
     order.setPayStatus(PayStatus.SUCCESS);
        orderRepository.save(order);

        //2、插入支付记录
     PayRecord record= RecordFactory.getSuccessRecord(order,result);
        recordRepository.insert(record);

        //3、插入订单日志
     OrderLog log = OrderFactory.getPaidLog(order);
        logRepository.insert(log);

        //4、通知财务系统,支付成功
     NotifyLog notifylog= NotifyFacotry.getSuccessNotify(order);
        nofifyService.notify(notifylog);

    }

    上述做法没有合适的关注点,无法把主线找到,随着随着业务扩大,修改代码是一件高风险的事情。

 

    换另一种方式来处理这些问题。

    1、发现该业务的主线。

    2、分析主线中的每一个活动会给系统带来什么变化。而这些变化就是主线所要传递的消息。

    3、把事件通知给相关对象。

 

    以上述例子为例

    可以得知 【更新订单状态】和【插入支付记录】是整个业务的主线。 【更新订单日志】和【通知支付系统,回到成功】是由于订单支付成功而引发的。

    因此在代码实现中,可以这样写

public class PurchaseOrder {

    public void notifyOrderPaid(List<OrderListener> listeners){
        for(OrderListener listener:listeners){
            listener.onOrderSuccessPaid(listener);
        }
    }
}

public  interface OrderListener{

    public void onOrderSuccessPaid(PurchaseOrder order);
}

public class LogListener implements OrderListener{
    private  LogRepository logRepository;
    public void onOrderSuccessPaid(PurchaseOrder order){
        Log log = OrderFactory.getPaidLog(order);
        logRepository.insert(log);
    }
}
public class FinanceListener  implements  OrderListener{
    private FinanceService financeService;
    public void onOrderSuccessPaid(PurchaseOrder order){
        NotifyLog notifylog= NotifyFacotry.getSuccessNotify(order);
        nofifyService.notify(notifylog);
    }
}
public class OrderService{
      public void successToPay(PurchaseOrder order,PayResult result){
         //主线          

      order.setPayStatus(PayStatus.SUCCESS);
         orderRepository.save(order);
         PayRecord record = RecordFactory.getSuccessPaidRecord(order,result);
         payRecordRepository.sae(record);

         //事件
      List<OrderListener> listeners =new ArrayList<OrderListener>();
         listeners.add(new FinanceListener());
         listeners.add(new LogListener());
         order.notifyOrderPaid(listeners);
      }
}

 

   一旦有新的业务增加时,应该考虑到它是属于主线,还是属于事件。我们的代码就不容易走向混乱。

 

 

 

分享到:
评论
12 楼 p4nny 2011-06-29  
18行代码变44行代码了
11 楼 raoliv 2011-06-29  
这个贴应该发到jdon去。
10 楼 Saito 2011-06-28  
这样的写法是很冗余的,你需要的其实是一个state-machine.

同步事件其实就是反射调用,真正有意义的是异步事件.

可以看一下这个是否满足你的需求.

1> 支持同步异步调用
2> 支持生成流程状态图
3> 有miniDSL支持
4> signal模式的调用.
5> 每种状态的三个signal插入点.
6> Rihno表达式判断
7> 无jar包依赖,适合你连代码一同co过去.放入项目

非Java style且没什么用的Java有限状态机.

里面有一个example,可以clone下来跑一下.(具体源码去github参考最新.

将主逻辑转移到状态机里面,业务代码主要用于启动特定的状态机.

像通知这样的需求,走异步事件模式是很划得来.

串行的逻辑做上下文参数维持用context贯通.
9 楼 luzhecheng 2011-06-28  
sing100star 写道


2、add Listener(),并不是用来控制循序。而是把【对OrderPaid事件感兴趣的listener】添加PurchaseOrder ,以便于通知




既然不控制执行顺序,你能确保你的业务逻辑里没有这样的需求?
8 楼 yunchow 2011-06-28  
也只是玩玩,没什么实际价值,如果所有业务这么来写,那才叫混乱,不说别的,这样会难以理解,也不好调试等等
7 楼 sing100star 2011-06-28  

1、业务上发生主线,必然会触发事件。但是事件响应方没有必然的联系。比如iphone4上市,有人会抢购,有人无所谓,但这些都不应影响iphone上市这个主线。

2、add Listener(),并不是用来控制循序。而是把【对OrderPaid事件感兴趣的listener】添加PurchaseOrder ,以便于通知



6 楼 bradwoo8621 2011-06-28  
observer
5 楼 luzhecheng 2011-06-28  
处理一般的业务逻辑可能会有先后顺序,你通过add Listener的先后顺序来控制Listener处理事件,我觉得不符合事件驱动模型。
4 楼 水痕2000 2011-06-28  
通常的做法如下
所有人都看得懂
一看就知道系统做了啥.
Listener 看不懂.没办法.
Listener 和 通常做法区别在于:
主线和Listener是否是一个人去写;
如果2个人去写,用Listener,业务代码隔离.
一个人去写,还是通常做法,别人读得懂
3 楼 agapple 2011-06-27  
如果 “主线”和“事件”是必然存在的一种业务关系。例如业务上发生主线,必然会触发事件。那你在设计domain的时候就应该将事件的动作封装到对应的save动作上。
这样,对与Action使用来说都只关系你的save动作。事件动作只不过是domain service中的某段业务代码,这时候在service内部你可以随意设计

如果你所谓的“主线”和“事件”不满足必然的关系,你搞这个就是搬起石头砸自己的脚,过度设计的一种
2 楼 sing100star 2011-06-27  
同步事件:
    现阶段的Web请求都是基于Request/Response的方式,一次响应对应一个线程,利用Spring的OpenSessionInView,可以 保证 一个线程只有一个数据库连接。不管是【主线】还是【事件】都用同样的数据库连接,事务也会得到统一的控制。

异步事件:
    我还没有特别关注,但是曾经看奥金蝶的Apusic OperaMasks中有关异步事件的案例http://infocenter.apusic.com/help/index.jsp?topic=/operamasks-sdk/output/eclipse/message_bus.html。
    你可以查看下:)
1 楼 freish 2011-06-26  
如果所谓的“事件”中的异常能影响主线是否回滚的话,该如何清晰的处理?

如果“事件”用异步方式来做,这种情况又该如何处理

相关推荐

    如何使用主线程异常捕获错误例子C#.net源代码编写

    本文将详细探讨如何在C#.NET中编写源代码来捕获主线程的错误。 首先,我们需要了解C#中的异常处理结构。异常处理通常通过`try-catch`块来实现,它可以捕获并处理在`try`块内抛出的任何异常。但是,对于主线程的异常...

    c# 自定义线程事件 异步挂接主线程 实用版2

    总的来说,理解和掌握C#中的自定义线程事件、异步操作以及进度条同步对于编写高效、用户友好的多线程应用程序至关重要。通过合理运用这些技术,开发者可以构建出更强大的后台处理逻辑,同时提供实时反馈,提升用户...

    如何从子线程更新主线程数据实例C#.net源代码编写

    为了解决这个问题,我们需要使用特定的方法来委托更新给主线程。 首先,我们需要了解几个关键的概念: 1. **Invoke/BeginInvoke**:这是.NET Framework提供的机制,允许非UI线程安全地调用UI线程上的方法。`...

    c#+中程序后台运行代码

    例如,使用`HttpApplication`的生命周期事件或`BackgroundWorker`组件来执行后台任务。 6. **SQLDBA**:与C#后台运行代码相关的可能还包括数据库操作。SQLDBA(SQL Database Administrator)涉及到SQL Server的管理...

    手形掌纹特征提取软件和QTC++下的源代码

    手形特征通常包括手指长度比例、关节弯曲度、手指与手掌连接的方式等,这些可以通过几何分析来提取。而掌纹特征主要关注其自然纹理,如主线、细线、纹路的方向和结构。这些特征的提取通常采用图像处理和模式识别技术...

    关于编写性能高效的javascript事件的技术

    DOM0级事件处理的事件属性命名遵循“on+事件名称”的规则,且整个属性都是小写字母,例如onclick、onmouseover等。因为DOM元素在JavaScript代码中本质上是JavaScript对象,所以从对象的角度来看,这种事件处理方式也...

    以同步方式编写异步代码_WriteAsynchronousCodeAsIf it'sSynchronous_javascript

    标题“以同步方式编写异步代码_WriteAsynchronousCodeAsIf it'sSynchronous_javascript”所指的就是使用`async/await`来实现这一目标。这个话题的核心在于理解如何使用这些新特性,并将异步操作封装成易于理解和执行...

    用VB.NET编写的记事本程序源代码

    VB.NET通过事件处理机制使得我们可以编写代码来响应这些事件。例如,当用户点击“保存”按钮时,我们需要编写相应的事件处理函数来执行保存操作。 5. **多线程**:虽然基础的记事本程序通常在主线程中运行,但如果...

    EventSample_C#事件范例_thereb9a_事件_事件触发_

    这可以通过在事件字段上调用+=操作符来实现: ```csharp myObject.MyEvent += OnMyEvent; ``` 这里,`OnMyEvent`是事件处理程序方法,它必须与事件委托类型兼容。 2. 发布(Publishing)事件:当状态改变发生时,...

    如何编写高效代码

    ### 如何编写高效代码 在IT领域,尤其是针对Android平台的开发,编写高效代码是确保应用程序性能的关键。本文将深入探讨高效代码编写的核心原则与实践技巧,帮助开发者优化程序,提升用户体验。 #### 引言 ...

    FreeSwitch完整的自定义模块定义和改善自定义事件的例子

    1. 使用异步处理:避免阻塞主线程,提升系统性能。 2. 错误处理:确保对可能出现的错误情况进行充分的处理和记录。 3. 日志和调试:添加详细的日志输出,便于问题排查。 4. 模块配置:允许用户通过配置文件自定义...

    主线程等待子多线程(无结果返回)执行完成再继续执行

    在Java中,主线程可以通过调用子线程的`join()`方法来等待该子线程结束。`join()`会阻塞当前线程(即主线程),直到被调用的子线程执行完毕。例如: ```java Thread childThread = new Thread(() -&gt; { // 子线程...

    Android-Kotlin编写的事件总线库

    总的来说,Kotlin编写的事件总线库为Android开发者提供了高效、灵活的组件间通信方式,结合Kotlin的特性和Android的开发实践,能够构建出稳定且易于维护的应用程序。通过理解并运用这些知识点,开发者能够更好地理解...

    JavaScript_事件驱动应用程序的低代码编程.zip

    JavaScript是一种广泛应用于Web开发的脚本语言,以其灵活性和易用性著称。在JavaScript中,事件驱动编程是一...通过学习这个主题,开发者可以更高效地创建响应式的Web应用和自动化流程,同时减少手动编写代码的工作量。

    QT多线程编程、主线程与子线程交互数据

    // 在这里编写子线程的代码 } }; ``` 子线程与主线程间的数据交互是多线程编程中的重点。QT提供了一些安全机制,如信号槽(Signals & Slots)机制,确保在多线程环境中安全地传递数据。信号和槽是QT的事件驱动...

    进度条例子(C#代码编写)

    下面我们将深入探讨如何使用C#编写进度条的相关知识点。 1. **WinForms中的ProgressBar控件** 在Windows Forms应用中,我们可以使用`ProgressBar`控件来创建进度条。首先,你需要在设计视图中添加这个控件到窗体上...

    girlfriend尝试一种新的开发方式来改变这种现状,它通过将不同功能的插件按照工作流进行组合的方式来编写脚本.zip

    标题提到的"girlfriend尝试一种新的开发方式"可能是指一个名为"girlfriend"的项目或框架,它旨在改变传统脚本编写的方式,尤其是针对Python环境。这个项目似乎采用了一种模块化、插件化的理念,允许开发者根据工作...

    C#编写坦克大战源代码

    本篇文章将深入探讨由C#语言编写的坦克大战游戏的源代码,通过分析和解释关键部分,为读者提供一个理解和应用C#编程语言的实践案例。 首先,C#是一种面向对象的编程语言,广泛应用于Windows平台和Unity3D游戏开发。...

    编写高质量javascript代码的68方法

    16. **事件委托**:通过事件冒泡机制,使用事件委托来优化事件处理,减少内存占用。 17. **性能优化**:合理使用`requestAnimationFrame`,避免阻塞主线程。 18. **DOM操作优化**:尽量减少DOM操作,使用批量操作...

    主线程控制ProgressDialog的可见性

    在Android开发中,ProgressDialog是一种常用的UI组件,用于在执行...理解这些概念有助于编写出更健壮的异步处理代码,同时保证用户体验的流畅性。通过深入研究源码和实践,开发者可以更好地掌握Android的UI更新机制。

Global site tag (gtag.js) - Google Analytics