`
kong0itey
  • 浏览: 308333 次
社区版块
存档分类
最新评论

架构演进-实例篇(转载)

 
阅读更多

1引言

在标题的取名上,不敢说颇费心机,也算得上花费了一点功夫的。首先想到的是“架构设计过程”,又觉得是不是太大了,因为例子比较局部,不是很完整。 叫做“结构变化过程”可能更好点。但是又怕名字取的小气了,进来的人少,参与讨论的就更少了,最终还是取了这个有点忽悠人的标题“架构演进”。

今天的这个架构演进,使用系统中一个局部的实例进行推导和演进,一起来观察一下,架构是如何不满足需求的?架构如何演进?更好的架构应该具备哪些条件?有没有更好的呢?

业务场景

payment1 图1 业务场景图

从上图可以看出,就是一个电子商务网站常见的支付、支付的后续处理,这样一个业务场景。支持多种支付方式,目前包括银联、支付宝,还有平台账户。平台账户就是注册用户将资金存储在平台为用户建立并维护的一个账户里,购买平台的产品,可以使用平台账户中的资金进行支付。

2业务流程

  1. 首先用户选择商品。
  2. 下单,进行支付。
  3. 选择支付方式。
  4. 使用相应支付方式进行支付。第三方支付,会跳转到第三方的支付页面进行支付。
  5. 平台进行支付的后续处理,包括成功之后的修改状态等,还包括失败之后的记录标记等。

第三方的支付,在打开第三方支付界面的时候,会告诉它一个平台的回调地址,支付之后,通过回调地址接收第三方支付的结果,然后进行后续处理。使用平台账户支付,就直接进行后续处理就可以了。

当然,这其中还会有一些细节,不在我们的讨论范围。例如:使用平台账户进行支付,判断账户金额是否充足。使用第三方支付,是否记录第三方支付的完整过程,以及完整的支付流程。等等具体的业务细节均不在今天的讨论范围。

 

3初级架构-用存储过程搞定它

回调地址接收两个参数,一个是订单编号,一个是标志。标志说明是成功还是失败,或者是更加详细的信息。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
CREATE PROCEDURE Proc_PaymentHandle
     @OrderSeqNo VARCHAR (36),    --订单编号
     @ReturnCode VARCHAR (10),    --返回状态码
     @PaymentManner CHAR (1)     --支付方式:1银联,2支付宝,3平台账户
AS
BEGIN
     IF(@PaymentManner= '1' )
     BEGIN
         --更新订单状态
         --更新银联支付信息
         RETURN ;
     END
     ELSE IF(@PaymentManner= '2' )
     BEGIN
         --更新订单状态
         --更新支付宝支付信息
         RETURN ;
     END
     ELSE IF(@PaymentManner= '3' )
     BEGIN
         --更新定的状态
         --更新平台账户支付信息
         RETURN ;
     END
END

配合一段C#代码,判断一下支付方式,然后给存储过程传递参数。这样写的话,上面的这个存储过程很容易就超过1k行了,相信大家也写过1k行以上的存储过程,也维护过这样的存储过程,知道个中的酸甜苦辣。

如果说那一天我们增加了一种支付方式,需要修改的地方包括哪些呢?

界面要修改,存储过程要打开修改,调用的C#代码要修改。真是有点麻烦,最主要的是容易改错了,误改了不应该动的地方才是最要命的。好吧, 我们简单分离一下。每种支付方式一个存储过程,把对于支付方式的判断放在代码中,每种支付对应一个代码中的方法。这样需要增加一种的话,只要改改支付方式 判断的代码,然后重新写一个存储过程,重新写一个方法调用一下新的存储过程就可以了。可是还有一个问题,更新订单状态好像大家都在做,如果哪一些还需要加 一些大家都需要做的事情呢?或者说修改一些大家都需要做的事情的细节?又或者说某两个支付方式需要增加一个处理流程呢?打开存储过程,狂修改吧!!!!

存储过程有几个不便利的地方:

  • 调试不方便
  • 测试不方便
  • 代码不能折叠,多了之后要拖动滚动条才能找得到
  • 逻辑运算、大规模计算是存储过程的弱项

存储过程的优势至少也有一个,就是修改之后,马上可以见到效果。不用编译。

4中级架构-在代码中分离对每种信息的更新

之前的架构代码中有很多的重复地方,例如:对于订单信息的更新。如何把重复降低呢?降低重复也就集中了代码,集中了将来也好维护。而且把它分离出 来,独立出来,好像更好点,在需要的地方调用就可以了。如果需要变更订单的更新细节,只要修改一下更新细节就可以了,不需要动支付的代码。减小犯错误的概 率。

首先,将各种更新信息独立出来。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class OrderRepository2
    {
        public void UpdateState()
        { throw new System.Exception(); }
    }
    public class PlatformAccountRepository2
    {
        public void Update()
        { throw new System.Exception(); }
    }
 
    public class ZhifubaoRepository2
    {
        public void Update()
        { throw new System.Exception(); }
    }
    public class YinlianRepository2
    {
        public void Update()
        { throw new System.Exception(); }
    }

 

使用下面的方法进行支付的后续处理。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void HandlePaymentResult(PaymentManner2 paymentManner, string orderSeqNo)
         {
             switch (paymentManner)
             {
                 case PaymentManner2.PlatformAccount :
                     var platformService = new PlatformAccountPaymentResultHandleService2();
                     platformService.Handle(orderSeqNo);
                     break ;
                 case PaymentManner2.Yinlian :
                     var yinlianService = new YinlianPaymentResultHandleService2();
                     yinlianService.Handle(orderSeqNo);
                     break ;
                 case PaymentManner2.Zhifubao :
                     var zhifubaoService = new ZhifubaoPaymentResultHandleService2();
                     zhifubaoService.Handle(orderSeqNo);
                     break ;
 
             }
         }
?
1
   
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public enum PaymentManner2
    {
        Zhifubao,
        Yinlian,
        PlatformAccount
    }
    public class ZhifubaoPaymentResultHandleService2
    {
        private OrderRepository2 _orderManagement;
        private ZhifubaoRepository2 _zhifubaoManagement;
 
        public void Handle( string orderSeqNo)
        {
            using (TransactionScope scope = new TransactionScope())
            {
                _orderManagement.UpdateState();
                this ._zhifubaoManagement.Update();
 
                scope.Complete();
            }
        }
 
    }
    public class YinlianPaymentResultHandleService2
    {
        private OrderRepository2 _orderManagement;
        private YinlianRepository2 _yinlianManagement;
 
        public void Handle( string orderSeqNo)
        {
            using (TransactionScope scope = new TransactionScope())
            {
                this ._orderManagement.UpdateState();
                this ._yinlianManagement.Update();
 
                scope.Complete();
            }
        }
    }
    public class PlatformAccountPaymentResultHandleService2
    {
        private OrderRepository2 _orderManagement;
        private PlatformAccountRepository2 _platformAccountManagement;
 
        public void Handle( string orderSeqNo)
        {
            using (TransactionScope scope = new TransactionScope())
            {
                this ._orderManagement.UpdateState();
                this ._platformAccountManagement.Update();
 
                scope.Complete();
            }
        }
 
    }

 

增加支付方式的话,新建一个HandleService类,写一些处理代码,然后在public void HandlePaymentResult(PaymentManner2 paymentManner, string orderSeqNo)方法的switch中增加一个case就可以了。

但是页面的可选支付方式还是写死了,没有动态的变化,支付方式是否可以动态配置呢?而且可以方便的测试呢?例如:虽然我还没有银联的接口,但是我想 测试一些,银联支付之后平台的处理是否正确,该更新的信息是否都更新了呢?没有银联的接口,是不是就不能做了呢?有没有办法解决呢?

答案是:有。

还有就是上面的switch。。。case,好像会很长,也很丑,这个地方能否改进呢?很多人在学习了重构之后,会提出很多的方法来解决这个问题,我们再后面也一块来解决一下。

5高级架构-少用存储过程处理业务的灵活架构

我们的高级架构有几个目标

  • 减少存储过程中的业务逻辑,让存储过程更加纯粹的做事,做它擅长的事情。
  • 可以灵活的增加或者减少支付方式。达到在增加或者减少支付方式的时候,尽量少的修改代码,尽量减少依赖。减少支付对于支付方式的依赖,支付方式对于后续处理的依赖。
  • 代码结构更加清晰。

为了达到上面的几个目标,计划独立几个部分。

  • 支付方式的管理。
  • 每一种支付方式的处理过程。这个在中级架构里面已经做的差不多了,这里会做的更好一点,抽象这个支付处理过程。

还有就是要隐藏支付方式和具体的支付方式处理过程映射代码。具体的支付方式指的是:银联或者是支付宝这种具体的一种支付方式。目的就是让对于支付订单的处理独立化,固定化,支持变化。

5.1支付方式的管理

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public enum PaymentManner1
{
     Zhifubao,
     Yinlian,
     PlatformAccount
}
 
public class PaymentMannerParams
{
     /// <summary>
     /// 地址还是内部方法
     /// </summary>
     public UriOrFunction UriOrFunction { get ; set ; }
    /// <summary>
    /// 地址
    /// </summary>
     public string Uri { get ; set ; }
     /// <summary>
     /// 方法名
     /// </summary>
     public string FunctionName { get ; set ; }
 
 
     enum UriOrFunction
     {
         Uri,
         Function
     }
}
 
public class PaymentMannerManagement1
{
     public Dictionary<PaymentManner1, PaymentMannerParams > FindAvailableManner( decimal moneyOfPay)
     {
         throw new System.Exception();
          
     }
}

通过FindAvailableManner方法获取支付方式。每种支付方式PaymentManner,都带有一个参数实体 PaymentMannerParams,里面的UriOrFunction来决定是通过网页还是内部方法来支付,Uri就跳转到Uri就可以 了,Function就调用FunctionName中的方法就可以了。支付的时候用下面的Pay先获取支付方式信息,然后根据每种支付方式的参数来决定 具体的支付。   

 public class OrderManagement1
    {
        public void  Pay(decimal money)
        {
            var manner= new PaymentMannerManagement1().FindAvailableManner(money);
            //后续支付
        }
    }

之前说的,如果银联还没有接口,或者接口暂时不能用了,想测试一下后续的处理,就可以将银联这种Manner的UriOrFunction设置为Function,现用内部的方法来测试后续的处理是否正确。等可以用的时候,在变更为Uri就可以了。

5.2支付过程的抽象

通过建立支付处理的接口,将支付处理的代码抽象成下面的样子。

?
1
2
3
4
5
6
7
8
public class Service1
     {
         public void HandlePaymentResult(PaymentManner1 paymentManner, string orderSeqNo)
         {
             IPaymentResultHandleService1 handleService = PaymentResultHandleServiceFactory1.GetService(paymentManner);
             handleService.Handle(orderSeqNo);
         }
     }

这个处理的代码,原则来说以后都不需要修改了。后面要做的就是定义一种新的支付方式枚举量,然后实现IPaymentResultHandleService1 接口,写一些处理的代码就可以了。

5.3完整代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;
 
namespace ConsoleApplication1
{
 
     public class Service1
     {
         public void HandlePaymentResult(PaymentManner1 paymentManner, string orderSeqNo)
         {
             IPaymentResultHandleService1 handleService = PaymentResultHandleServiceFactory1.GetService(paymentManner);
             handleService.Handle(orderSeqNo);
         }
     }
 
 
     public class OrderManagement1
     {
         public void   Pay( decimal money)
         {
             var manner= new PaymentMannerManagement1().FindAvailableManner(money);
             //后续支付
         }
     }
 
 
 
     public enum PaymentManner1
     {
         Zhifubao,
         Yinlian,
         PlatformAccount
     }
 
     public class PaymentMannerParams
     {
         /// <summary>
         /// 地址还是内部方法
         /// </summary>
         public UriOrFunction UriOrFunction { get ; set ; }
        /// <summary>
        /// 地址
        /// </summary>
         public string Uri { get ; set ; }
         /// <summary>
         /// 方法名
         /// </summary>
         public string FunctionName { get ; set ; }
 
 
         enum UriOrFunction
         {
             Uri,
             Function
         }
     }
 
     public class PaymentMannerManagement1
     {
         public Dictionary<PaymentManner1, PaymentMannerParams > FindAvailableManner( decimal moneyOfPay)
         {
             throw new System.Exception();
              
         }
     }
 
     public class PaymentResultHandleServiceFactory1
     {
         private static   PaymentResultHandleServiceFactory1()
         {
             _serviceMap = new Dictionary<PaymentManner1, IPaymentResultHandleService1>();
             _serviceMap.Add(PaymentManner1.PlatformAccount, new PlatformAccountPaymentResultHandleService1());
             _serviceMap.Add(PaymentManner1.Yinlian, new YinlianPaymentResultHandleService1());
             _serviceMap.Add(PaymentManner1.Zhifubao, new ZhifubaoPaymentResultHandleService1());
         }
 
         private static   Dictionary<PaymentManner1 , IPaymentResultHandleService1> _serviceMap;
 
 
 
         public static IPaymentResultHandleService1 GetService(PaymentManner1 paymentManner )
         {
             return _serviceMap[paymentManner];
         }
 
     }
 
     public interface IPaymentResultHandleService1
     {
         void Handle( string orderSeqNo);
     }
 
 
 
     public class ZhifubaoPaymentResultHandleService1:IPaymentResultHandleService1
     {
         private OrderRepository1 _orderManagement;
         private ZhifubaoRepository1 _zhifubaoManagement;
 
         public void Handle( string orderSeqNo)
         {
             using (TransactionScope scope = new TransactionScope())
             {
                 _orderManagement.UpdateState();
                 this ._zhifubaoManagement.Update();
 
                 scope.Complete();
             }
         }
 
     }
     public class YinlianPaymentResultHandleService1 : IPaymentResultHandleService1
     {
         private OrderRepository1 _orderManagement;
         private YinlianRepository1 _yinlianManagement;
 
         public void Handle( string orderSeqNo)
         {
             using (TransactionScope scope = new TransactionScope())
             {
                 this ._orderManagement.UpdateState();
                 this ._yinlianManagement.Update();
                  
                 scope.Complete();
             }
         }
     }
     public class PlatformAccountPaymentResultHandleService1:IPaymentResultHandleService1
     {
         private OrderRepository1 _orderManagement;
         private PlatformAccountRepository1 _platformAccountManagement;
 
         public void Handle( string orderSeqNo)
         {
             using (TransactionScope scope = new TransactionScope())
             {
                 this ._orderManagement.UpdateState();
                 this ._platformAccountManagement.Update();
 
                 scope.Complete();
             }
         }
 
     }
     public class OrderRepository1
     {
         public void UpdateState()
         { throw new System.Exception(); }
     }
     public class PlatformAccountRepository1
     {
         public void Update()
         { throw new System.Exception(); }
     }
 
     public class ZhifubaoRepository1
     {
         public void Update()
         { throw new System.Exception(); }
     }
     public class YinlianRepository1
     {
         public void Update()
         { throw new System.Exception(); }
     }
 
}

 

6总结

类的依赖最好使用抽象,避免具体类的直接引用。

尽量不要再存储过程中处理业务,在系统越做越大,你会越来越赞同我的说法。原因至少两点:1维护累死人,2数据库不擅长数值计算和处理。

职责单一,功能独立,代码分离

 

文章来源:http://www.cnblogs.com/virusswb/archive/2011/08/31/2160708.html

架构演进-实例篇

分享到:
评论

相关推荐

    智东西公开课-类脑芯片的架构演进-灵汐科技首席架构师冯杰.pdf

    智东西公开课-类脑芯片的架构演进-灵汐科技首席架构师冯杰.pdf

    分还是合?58到家订单中心架构演进-沈剑.pdf

    在探讨58到家订单中心架构演进的过程中,涉及到的关键技术知识点可以从以下几方面进行展开: ### 订单中心业务介绍 订单中心的核心业务是处理数据量大且并发量大的订单信息。它主要面临的问题包括不同业务订单的...

    京东交易架构演进-高可用服务的保障-杨超

    京东是中国著名的电子商务公司,随着业务量的激增和用户需求的提升,其交易平台架构也在不断演进,以保障高可用性和应对高并发场景。架构师杨超在分享中详细阐述了京东交易架构的演进历程,重点讲述了大促中的技术...

    2-5、MySQL高可用架构演进-吴炳锡@知数堂.pdf

    MySQL高可用架构演进-吴炳锡。 1. 什么是高可用 2. 第一代传统复制: MHA及使用架构 3. 第二代基于GTID复制:GTID+Binlog server At Booking & Facebook 4. 第三代增强半同步复制:GTID+增强半同步及多IDC架构及...

    01-从NewSQL到全新的HTAP分布式架构演进-张潇.pdf

    ### MatrixOne架构演进之路 #### 张潇自我介绍 张潇在数据库领域有超过十年的经验,早期曾在金融、教育和商业地产等行业担任全职DBA。2021年至今,他转为担任矩阵起源公司的产品架构师,期间深入研究并熟悉了Oracle...

    百度网盘工程架构演进-徐亚非1

    【百度网盘工程架构演进】是百度网盘在技术上的一个重要历程,主要由百度资深研发工程师徐亚非分享。该演讲涵盖了多个关键知识点,包括项目背景、架构设计、技术选型以及工具链的演进。 1. **项目介绍**: 百度...

    阿里直播平台架构演进-陈康贤

    阿里直播平台架构演进的知识点涵盖了直播平台的发展、架构变迁、技术细节和面临的挑战。 首先,直播行业在互联网技术发展的推动下,已经从曾经的高门槛专业领域,转变为普罗大众都可以参与的领域。陈康贤通过数据和...

    如何用Go支撑海外电商架构演进-易乐天-小米

    在探讨如何使用Go语言(又称Golang)来支撑小米国际电商平台架构的演进过程中,我们可以从以下几个方面梳理出相关的知识点。 首先,国际电商平台的业务背景对技术架构的要求较高。用户量大、业务多变、并发数高以及...

    苏宁库存系统演进及架构介绍 - 2016 - 司孝波 - 杭州演讲 - x1.pptx

    苏宁库存系统演进及架构介绍 - 2016 - 司孝波 - 杭州演讲 - x1.pptx

    58同城WFS系统架构演进-SACC2021年中国系统架构师大会.pdf

    本内容将详细介绍58同城WFS系统架构的演进过程,包括其基本原理、业务场景适应性以及在不同阶段架构的设计和优化。 ### WFS系统概述 WFS是58同城后端高阶架构师钟昌寿在演讲中介绍的核心主题。WFS作为分布式文件...

    业务快速交付低代码架构演进-SACC2021年中国系统架构师大会.pdf

    在此次SACC2021中国系统架构师大会上,京东科技数字城市群总架构师梁福坤做了主题为“业务快速交付低代码架构演进”的报告,分享了他对低代码架构的深入理解和未来发展的思考。 一、低代码简介 低代码开发平台(Low...

    高速发展的饿了么订单系统架构演进 - 饿了么平台交易支撑负责人 - 石佳宁

    饿了么在高速发展中订单系统的演变过程经历了几个阶段,技术上的并发支撑,服务化解耦,重构拆 分以适应新的业务模型和领域等等.其中涉及到很多与传统电商不一样的痛点.... 了解核心架构应用如何在业务推动下发展的;

    系统架构方法---基础篇

    本课程基础篇主要目的是帮助初学者掌握基本的系统架构理念,通过实例和图示进行深入浅出的讲解,以期让更多的人能理解和运用架构知识。 首先,我们要理解什么是架构。Mary Shaw的观点指出,架构是计算组件及其交互...

    电子电器架构 --- 电子电气架构演进的趋势2024.08.31.docx

    在汽车工业的历史长河中,电子电气架构的演进一直是技术革新的重要体现,其发展历程不仅体现了汽车智能化的不断追求,也反映了时代需求的不断变化。随着互联网、人工智能、物联网等技术的飞速发展,汽车作为交通工具...

    闲鱼从零到千万DAU的应用架构演进.pdf

    闲鱼从零到千万DAU的应用架构演进.pdf这篇文章主要介绍了闲鱼从零到千万DAU的应用架构演进,文章从闲鱼业务介绍开始,讲述了闲鱼市场本质、高性价比的商品市场、闲鱼业务特点、业务形态决定技术架构演进等内容。...

    《大型网站技术架构演进与性能优化》

    《大型网站技术架构演进与性能优化》这本书深入探讨了互联网行业中大型网站在技术架构上的发展路径和性能优化策略。随着互联网的飞速发展,大型网站的架构设计和性能优化成为了决定企业竞争力的关键因素。本篇文章将...

    明星讲师-黄浩-ASSZ2018-下一代分布式体系架构的理念与演进-黄浩

    ### 下一代分布式体系架构的理念与演进 #### 明星讲师-黄浩-ASSZ2018 ##### 分布式系统架构概述 在过去的二十年里,随着互联网技术和业务需求的飞速发展,分布式系统架构经历了多次重大变革。从最初的单体应用到...

    基于云原生架构的PaaS平台演进之路.pdf

    本知识点将详细探讨云原生架构的PaaS平台演进之路,以及相关技术栈的应用和发展。 首先,PaaS(Platform as a Service)平台为开发者提供了构建、测试和部署应用程序的平台和解决方案。在教育行业中,PaaS平台通过...

Global site tag (gtag.js) - Google Analytics