- 浏览: 304762 次
文章分类
最新评论
-
流年末年:
那四个参数还是没看懂.....能不能解释下showPassst ...
我写的密码强度验证方法(原创) -
kingcs2008:
// 验证pws.jsshowPassstrength(&qu ...
我写的密码强度验证方法(原创) -
h957355152:
请问博主这个怎么用呢?我直接放到jsp里面调用showPass ...
我写的密码强度验证方法(原创) -
qq_15138059:
我写的全国省市县三级联动菜单,拿出来和大家分享了(原创) -
valenon:
评论呢?从MAIL FROM命令开始貌似就出错了:500 Er ...
如何发送伪造的电子邮件
1引言
在标题的取名上,不敢说颇费心机,也算得上花费了一点功夫的。首先想到的是“架构设计过程”,又觉得是不是太大了,因为例子比较局部,不是很完整。 叫做“结构变化过程”可能更好点。但是又怕名字取的小气了,进来的人少,参与讨论的就更少了,最终还是取了这个有点忽悠人的标题“架构演进”。
今天的这个架构演进,使用系统中一个局部的实例进行推导和演进,一起来观察一下,架构是如何不满足需求的?架构如何演进?更好的架构应该具备哪些条件?有没有更好的呢?
业务场景
从上图可以看出,就是一个电子商务网站常见的支付、支付的后续处理,这样一个业务场景。支持多种支付方式,目前包括银联、支付宝,还有平台账户。平台账户就是注册用户将资金存储在平台为用户建立并维护的一个账户里,购买平台的产品,可以使用平台账户中的资金进行支付。
2业务流程
首先用户选择商品。 下单,进行支付。 选择支付方式。 使用相应支付方式进行支付。第三方支付,会跳转到第三方的支付页面进行支付。 平台进行支付的后续处理,包括成功之后的修改状态等,还包括失败之后的记录标记等。第三方的支付,在打开第三方支付界面的时候,会告诉它一个平台的回调地址,支付之后,通过回调地址接收第三方支付的结果,然后进行后续处理。使用平台账户支付,就直接进行后续处理就可以了。
当然,这其中还会有一些细节,不在我们的讨论范围。例如:使用平台账户进行支付,判断账户金额是否充足。使用第三方支付,是否记录第三方支付的完整过程,以及完整的支付流程。等等具体的业务细节均不在今天的讨论范围。
3初级架构-用存储过程搞定它
回调地址接收两个参数,一个是订单编号,一个是标志。标志说明是成功还是失败,或者是更加详细的信息。
12345678910111213141516171819202122232425CREATE
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中级架构-在代码中分离对每种信息的更新
之前的架构代码中有很多的重复地方,例如:对于订单信息的更新。如何把重复降低呢?降低重复也就集中了代码,集中了将来也好维护。而且把它分离出 来,独立出来,好像更好点,在需要的地方调用就可以了。如果需要变更订单的更新细节,只要修改一下更新细节就可以了,不需要动支付的代码。减小犯错误的概 率。
首先,将各种更新信息独立出来。
123456789101112131415161718192021public
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(); }
}
使用下面的方法进行支付的后续处理。
12345678910111213141516171819public
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
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556public
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支付方式的管理
1234567891011121314151617181920212223242526272829303132333435363738public
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支付过程的抽象
通过建立支付处理的接口,将支付处理的代码抽象成下面的样子。
12345678public
class
Service1
{
public
void
HandlePaymentResult(PaymentManner1 paymentManner,
string
orderSeqNo)
{
IPaymentResultHandleService1 handleService = PaymentResultHandleServiceFactory1.GetService(paymentManner);
handleService.Handle(orderSeqNo);
}
}
这个处理的代码,原则来说以后都不需要修改了。后面要做的就是定义一种新的支付方式枚举量,然后实现IPaymentResultHandleService1 接口,写一些处理的代码就可以了。
5.3完整代码
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170using
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
架构演进-实例篇
发表评论
-
全国学校和地区数据库
2012-04-08 03:14 2641全国学校和地区数据库 -
提升struts2的性能
2012-03-30 14:39 808freemarker 升级为2.3.14 og ... -
JAVA项目之SSH编码规范
2012-03-26 00:19 948编码规范目的:风格统 ... -
浅谈千万级PV/IP规模高性能高并发网站架构
2012-03-21 23:42 1316浅谈千万级PV/IP 规模高性能高并发网站架构 ... -
struts2的通用分页工具条
2012-03-07 11:17 1740java组件 package com.tag; im ... -
myeclipse中项目上面有红叉如何解决?
2012-03-06 13:50 6626项目中没有错误,却发现有一个红叉,怎么都消不掉,这是为什么呢? ... -
基于Compass2.2与Spring 结合建立索引的实例
2012-03-03 19:55 1141本实例建立在ssh ... -
数据库表设计的基本原则
2012-03-02 08:47 9791.动态数据和静态数据分离,比如统计作用的列comment_c ... -
struts1.x、struts2.x和springmvc浅析(转载)
2012-02-27 09:59 1043入住javaeye也要1年半了,第一次给自己的blog丰富点. ... -
testsaslauthd报 0: NO "authentication failed" 的问题
2012-02-17 00:39 4773输入 ./testsaslauthd -u userID -p ... -
CentOS5.3+Nginx0.7.57+Postfix+Extmail邮件系统安装配置
2012-02-17 00:37 1012、 ... -
中外伟人观之对比,架构
2012-02-16 20:59 397世界上每一个国家都有他们的伟人,但各国的伟人观却不 ... -
postfix用到的包
2012-02-16 15:20 788The Postfix RPM I produce use ... -
通过Telnet来发送邮件
2012-02-16 10:28 968有些时候我们通过写代码来发送邮件. 有些时候, 代码可以正 ... -
sendmail发件人显示为xxx@localhost.localdomain的解决办法
2012-02-15 22:07 5152大 | 中 | 小 1 ... -
消息提示的架构演进-理论篇(转载)
2012-02-05 18:02 725项目是一个互联网 ... -
通告(公告),消息(站内短信),提醒的设计<一>:通告(转载)
2012-02-05 18:00 13441 业务描述 首先我们 ...
相关推荐
01-从NewSQL到全新的HTAP分布式架构演进-张潇
智东西公开课-类脑芯片的架构演进-灵汐科技首席架构师冯杰.pdf
在探讨58到家订单中心架构演进的过程中,涉及到的关键技术知识点可以从以下几方面进行展开: ### 订单中心业务介绍 订单中心的核心业务是处理数据量大且并发量大的订单信息。它主要面临的问题包括不同业务订单的...
京东是中国著名的电子商务公司,随着业务量的激增和用户需求的提升,其交易平台架构也在不断演进,以保障高可用性和应对高并发场景。架构师杨超在分享中详细阐述了京东交易架构的演进历程,重点讲述了大促中的技术...
MySQL高可用架构演进-吴炳锡。 1. 什么是高可用 2. 第一代传统复制: MHA及使用架构 3. 第二代基于GTID复制:GTID+Binlog server At Booking & Facebook 4. 第三代增强半同步复制:GTID+增强半同步及多IDC架构及...
【百度网盘工程架构演进】是百度网盘在技术上的一个重要历程,主要由百度资深研发工程师徐亚非分享。该演讲涵盖了多个关键知识点,包括项目背景、架构设计、技术选型以及工具链的演进。 1. **项目介绍**: 百度...
阿里直播平台架构演进的知识点涵盖了直播平台的发展、架构变迁、技术细节和面临的挑战。 首先,直播行业在互联网技术发展的推动下,已经从曾经的高门槛专业领域,转变为普罗大众都可以参与的领域。陈康贤通过数据和...
在探讨如何使用Go语言(又称Golang)来支撑小米国际电商平台架构的演进过程中,我们可以从以下几个方面梳理出相关的知识点。 首先,国际电商平台的业务背景对技术架构的要求较高。用户量大、业务多变、并发数高以及...
苏宁库存系统演进及架构介绍 - 2016 - 司孝波 - 杭州演讲 - x1.pptx
电子电器架构 --- 电子电气架构演进的趋势2024.08.31
本内容将详细介绍58同城WFS系统架构的演进过程,包括其基本原理、业务场景适应性以及在不同阶段架构的设计和优化。 ### WFS系统概述 WFS是58同城后端高阶架构师钟昌寿在演讲中介绍的核心主题。WFS作为分布式文件...
在此次SACC2021中国系统架构师大会上,京东科技数字城市群总架构师梁福坤做了主题为“业务快速交付低代码架构演进”的报告,分享了他对低代码架构的深入理解和未来发展的思考。 一、低代码简介 低代码开发平台(Low...
饿了么在高速发展中订单系统的演变过程经历了几个阶段,技术上的并发支撑,服务化解耦,重构拆 分以适应新的业务模型和领域等等.其中涉及到很多与传统电商不一样的痛点.... 了解核心架构应用如何在业务推动下发展的;
本课程基础篇主要目的是帮助初学者掌握基本的系统架构理念,通过实例和图示进行深入浅出的讲解,以期让更多的人能理解和运用架构知识。 首先,我们要理解什么是架构。Mary Shaw的观点指出,架构是计算组件及其交互...
闲鱼从零到千万DAU的应用架构演进.pdf这篇文章主要介绍了闲鱼从零到千万DAU的应用架构演进,文章从闲鱼业务介绍开始,讲述了闲鱼市场本质、高性价比的商品市场、闲鱼业务特点、业务形态决定技术架构演进等内容。...
《大型网站技术架构演进与性能优化》这本书深入探讨了互联网行业中大型网站在技术架构上的发展路径和性能优化策略。随着互联网的飞速发展,大型网站的架构设计和性能优化成为了决定企业竞争力的关键因素。本篇文章将...
### 下一代分布式体系架构的理念与演进 #### 明星讲师-黄浩-ASSZ2018 ##### 分布式系统架构概述 在过去的二十年里,随着互联网技术和业务需求的飞速发展,分布式系统架构经历了多次重大变革。从最初的单体应用到...
本知识点将详细探讨云原生架构的PaaS平台演进之路,以及相关技术栈的应用和发展。 首先,PaaS(Platform as a Service)平台为开发者提供了构建、测试和部署应用程序的平台和解决方案。在教育行业中,PaaS平台通过...