本文读者基本要求:从事信息管理系统开发,略懂GOF设计模式及SOLID设计原则,对三层面向过程机械编码厌倦,而且不知道出路在何方,若是还掌握代码坏味和重构手法,那是极好的。前端
理论介绍-->实际经验-->总结反思git
严格分层架构模式的特色是上层只能访问相邻的下层,其余层次间的调用都不容许。三层架构就是一种严格分层模式,它把职责划分为界面展现、业务逻辑、数据访问三层,还有一个业务实体,前面三层都要依赖它,因此它并不构成一个层。结构如图1。程序员
三层架构的特色是一种面向过程的编程思想,特色以下:github
a. 业务实体类中基本上只有属性没有方法。数据库
b. 业务逻辑层的类基本上只有方法没有属性。编程
c. 将数据表结构映射为业务实体类是一个惯用作法,以致于有人将其称之为“传统”。这样的好处是只须要理解一套模型,可以经过自动化工具从数据表直接生成业务实体,还可以天然而然的经过自动化机制存储与检索业务实体。但对于复杂点的业务,这样作就是绝大部分问题的根源。设计模式
d. 当业务膨胀起来,须要划分模块的时候,咱们有个经常使用的变形:提取一个服务层出来,用来组合模块间的交互,还为业务逻辑层提供了一个防腐层,能够把记录日志、验证权限、处理异常等职责分配给服务层。结构如图2。缓存
上面介绍的就是咱们常说的三层架构,因为采用了严格分层模式,用户界面层是绝对不能跨过业务逻辑层调用数据访问层的,同理服务层也是不能调用数据访问层。可是图2都有四层了,那它仍是三层吗?这就须要见仁见智了,通常来讲仍是的。其实三层架构还有个更准确的名字----分层贫血领域模型架构,这样就无论多少层都能归纳了,可是这名字没有三层那么朗朗上口。前面名字中的领域模型指的是业务实体,贫血意思业务实体中没有或不多方法。安全
1.2.1 PetShop。网络
三层架构比较著名的例子就是PetShop,其技术内容比较丰富,MemberShip,ProfileProvider,各类接口,各类Factory,可替换的数据访问层,缓存机制,消息队列等技术,看起来很牛的样子。但它的领域模型却比较简单,连模块都没有划分,只能算个玩具。不少年前,见识还比较少的时候,微软就是我心中的神,只有微软提供的技术才是最正宗的,微软说的都是对的,没有用上微软提供的技术,内心就各类不对劲。后来学习设计模式,知道有个模式痴迷症(若是在编码中没有用上模式,内心就各类不对劲),才明白原来本身以前患上了微软痴迷症。在个人实际工做经历中,微软痴迷症患者不在少数。就PetShop而言,微软只是展现一下他的技术而已,初学者们不明觉厉,盲目地奉它经典,以致于固步自封,不明白软件开发的路还很长很长,每种技术都有它的适用场景,选择权永远都在本身的手上(或在团队领导的手上)。
1.2.2 本人实际工做经历。
参加工做的前几年,都在小公司,经历的都是一我的开发的小项目,有时有个Web前端或美工配合一下,信息系统嘛,主要功能固然就是存储、检索、展现数据,业务操做就是CRUD了,业务逻辑最多就是验证一下业务实体填写的正确性,数据表的数量也很是有限。那时的我,在三层架构的统治下,作着一个快(枯)乐(燥)的数据搬运工(从数据库搬到界面或从界面搬到数据库)。
长期重复枯燥的工做会让人感受前途无亮,穷则思变,结果就是人员的流动。对于短时间小项目来讲,人员流动根本不是个事,可是对于长期项目来讲,可能就没那么简单了,某些关键人物的离职,可能会引发很长期的震荡,接手的人加班、发脾气绝对是正常的(这视乎接手人员的技术水平),甚至可能使项目停滞不前。
终于,我顺从心里的呼唤,离开那个简单的环境,加入了一个比较复杂的长期项目。和之前同样,采用三层架构,信息系统项目嘛,CRUD就是基石,项目中绝大部分的工做就是搬运数据。不一样的是,开发人员有10个以上(人生中第一个团队开发);数据表超过200个(这是之前不敢想象的)。更加不一样的是,有些功能,它可能牵涉到了全部的数据表,作这样一个功能,首先要把全部关联到的数据表都找出来,理解清楚表与表之间的关系,比较痛苦的是别人写的代码你基本用不上,都要本身从头搞。对于那些平时只是埋头搞本身一块功能的人来讲,简直是要命。还有更要命的,不知道何时需求又变动了,而处理这个功能的人离职了。开始,接手的新人两眼泪汪汪求多给点时间,而领导不理解,之前谁谁不是很快就搞定了吗?那些站着说话不腰疼的同事说,这功能简单,这个、这个、还有这个表,那个、那个、还有那个表,这样再那样就解决了。我把这种协做方式成为嘴炮协做,真正的协做应该是代码层面的。新人无法辩驳通常最后会选择默默地加班。人员继续流动,这样的情形发生屡次以后,领导开始意识到,状况没那么容易了。特别是若是几个关键开发者都离职了,那境况更是难上加难。就算没有人离职,状况同样是愈来愈难,这我在后面的一个项目中有比较深入的体会,可是并非全部人都会把这种难归结于架构不对或团队开发水平还有待提高,他们会认为这是需求的问题或者其余同事的问题,还有人会认为这是正常的必然的无解的事情。若是一段时间复杂的功能变动多起来,加班就会成为常态,若是加班可以搞定,状况还不算最糟糕。“水很深,水太深,水不知道有多深”开始成为了团队的口头禅。比较幸运的是当时那个项目这样的功能不算太多。最后有人总结出一句名言:“谁遇到谁倒霉 ,忍忍就过去了”。说到这里,不少人可能会说,让全部开发人员的熟读全部数据表不就好了?实际状况是,除了关键的几我的,其余开发人员每每没有那个愿意把有限的生命浪费在阅读这些下个项目就毫无用处了的数据表上,并且表的数量可能会增加到没有任何一我的可以总体掌控的程度。并且一个牵涉多个模块的复杂功能,不能调动相关模块来协助,反而都得直接与数据库打交道,其余模块的逻辑也须要本身处理,这是单打独斗的套路,体现不了团队的协做与效率;再有就是不能复用那些久经考验的代码,致使重复代码慢慢积累,系统缺陷也比较多。并且由多人接手后,一旦有人理解出了误差,需求变动致使致命缺陷的概率会很高。
虽然项目组的生活氛围不错,时不时有经费给同事们出去吃完玩乐一下,可是不能预料何时需求就会提出一些“险恶”的功能,对人的精神也是一种考验。为了应付随时可能出现的各类险恶状况,我学习掌握了一些重构手法,学会用了UML来分析问题,还在项目中成功地应用了两个设计模式来解决一个棘手问题。可是在三层架构的大环境下,可以发挥的余地也是很是有限,有种有技术没地方用的感受,常有新建一个类不知道该往哪一个层放的状况。
后来,我还在另一个采用三层架构的长期项目里呆过,状况与上一个项目基本同样,除了人员比较上一个项目稳定不少。就三层架构实际遇到的问题,我咨询了一些项目经理朋友,他们的意见以下:
经理A:代码是不可能写成书上介绍那样规范好维护的。
经理B:需求是不可能稳定下来的,代码也是不可能稳定下来的。
经理C:项目到了后期代码乱?难道不都是这样吗?
Linus Torvalds :Bad programmers worry about the code. Good programmers worry about data structures and their relationships. (差的程序员纠结代码怎么写,好的程序员纠结数据结构和结构间的关系。)
三层架构的最大问题在于:实际应用中人们喜欢把内存模型和数据库模型保持一致。三层架构的大部分问题都是从这里衍生出来的。
数据库模型的粒度若是很小,那么大量的表链接很快就会让数据库跑不动了。
若是数据库模型的粒度若是很大(这是大部分项目的选择),代码的质量(重用性、稳定性、扩展性)就不好。因为没有从业务的角度去仔细定义每个对象,每一个人会根据本身的须要创建各类QueryModel或ViewModel,慢慢地类会多到想哭。或若是不创建各类Model,强行重用DataModel的话,那么接口提供的内容每每绝大部分都不是你想要的。
内存模型与数据库模型保持一致并不是天生的,这是有不少缘由形成的:
它建模的简单性让初学者没法拒绝,因为经验主义,以致于多年之后已经没有勇气去摆脱了;
没有专门论述三层与建模的书籍;
ORM工具误导,与数据表结构一致内存结构方便创建映射关系;
示范代码的误导,错误把示范代码当成产品代码;
等等......
种种误导致使不少人工做不少年后依然未能找到正确的路,忽略了一个重要的核心(业务建模)环节(业务模型要与代码的数据结构保持一致),可是他却坐上了项目领导的职位,这就是更大的误导了。以致于让人产生不管你去到那个公司都是同样的错觉(在不少人的经历中,这的确是事实,包括我本身),但事实不该该是这样的。
用户界面,领域模型,数据库它们应该具备同等的重要位置,领域模型在不少公司都是被忽略的角色。
咱们应该相信:优秀的软件必定是由优秀的开发者制做的,团队的协做方式应该在代码层面,代码复用能够下降缺陷和提高效率。而这些都指向你应该离开“传统”三层架构。
还有一些三层开发人员最终患上了数据库痴迷症,他坚信程序就应该作个搬运工,其余的事情都应该交给数据库来完成,业务逻辑也应该写进存储过程里面去。
优化层次关系-->重构到面向对象设计-->使用DDD相关模式深刻重构
上面讲到,三层是“分层贫血领域模型架构”,那么DDD则可称为“分层充血领域模型架构”。从名字上看,它们就有亲戚关系,有亲戚好办事,嘿!
三层到DDD的过程大致是这样的:首先推翻严格分层的理念,采用松散分层来从新定义服务层(松散分层的意思是上层能够访问下层,而不仅是相邻的下层),把调用数据访问层的职责交给服务层,接着把业务逻辑层移动到与业务实体在一块儿,再接着融合业务逻辑与业务实体,使之成为面向对象的设计,而后利用DDD的模式进行更深刻的重构。在DDD技术掌握的还不是那么扎实的时候,三层技术基本仍然可以继续使用。
因为目前的服务层职责是很是轻的,甚至有不少空壳的调用,因此平衡一下职责,把调用数据访问层的职责从业务逻辑层提高到服务层,须要的数据经过参数传递给业务逻辑层。这样,对于那些简单到无业务逻辑的CRUD就不须要去访问业务层了,直接调用数据访问层。
结构如图3,咱们看到业务逻辑与数据访问层已经没有依赖关系了。
而后咱们就能够把业务逻辑与业务实体移到一块。
而后把属于业务实体的逻辑迁移到实体类中。
上面简单单几句话和两张图就把问题搞定了,可是实际迁移过程当中,风险是很是大的,若是没有充分掌握重构知识,建议不要在正式产品代码上尝试。有些逻辑没法归类到任何一个业务实体上的,就让它留在原地,成为一个领域服务。有些逻辑连领域服务都没法归类的,就让它留在服务层,在坚持大方向的前提下,细节灵活处理,由于每次重构都可以让你对将来的路看到更清楚,极可能下一次重构后你就会为这些流浪逻辑找到合适的家了。全部的建议都只是建议,最终决定权在你的手上,受苦的人始终都是你本身。
一个事实是:掌握的编程思想越多,那么搬迁起来就越容易,假若编程功底太差,可能根本没法搬动,不建议初学者进行这些危险的试验,由于你必定会把事情搞砸的,若是你把事情搞砸了,请自我检讨一下是否是编程思想不太够用。
上面的过程并不是要你一步到位,你能够把代码重构到任何一个时刻,等待后面知识跟上了,再进行下一步的重构。
到目前为止,代码仍是那些代码,只是位置变了而已,因此若是严格按照重构手法进行,编译、运行应该都是没有问题的。就这样,在现有生活没有任何影响的状况下,你已经为你的职业生涯打开了另一扇门,不再怕编程技术拼不过那些年轻人了。
实际上,DDD只是让你从新回归到面向对象编程,没有什么更加神奇的魔法,固然DDD超越面向对象的地方在于对类的设计提出了更多的指导方法。
正式介绍一下DDD的分层架构,固然DDD的架构并不限于分层,如今还有六边形架构、CQRS、EventSourcing等技术能够选用,可是不要好高骛远,先把分层架构掌握好。原版分层结构如图5,改进版结构如图4,图4基本上就是图3的各个层换了名字,而且UI能够访问基础设施层。而图4与图5的区别在于,图4是基础设施依赖领域层,图5是领域层依赖基础设施层,这两层的关系倒置了。这样的倒置会更凸显领域层的核心地位,也有人认为这样已经算是六边形架构了。
2.2.1 DDD各层次职责解析
用户界面层:
原版----负责向用户展示信息以及解释用户命令。
补充---- MVC中V和C都属于UI层,V展示信息,C解析用户命令。UI像地图同样把各个控制器关联了起来。
应用层:
原版----很薄的一层,用来协调应用的活动。它不包含业务逻辑。它不保留业务对象的状态,但它保有应用任务的进度状态。
补充----协调应用的活动这句话太抽象了,我充实一下它:从数据访问中获取领域对象,调用领域对象的方法完成任务,而后再调用数据访问代码把领域对象的改变持久化。事务、权限检查、记录日志、处理异常的职责也归它管。这点和前面三层的服务层的职责实际上是同样的。
领域层:
原版----本层包含关于领域的信息。这是业务软件的核心所在。在这里保留业务对象的状态,对业务对象和它们状态的持久化被委托给了基础设施层。
补充----业务对象的持久化工做咱们已经提高到应用层了,通常状况下,这层最好不要涉及资源库的调用,可是并不绝对。资源库的抽象要么在领域层中,要么提高到了“应用程序框架”,领域层是不会依赖基础设施的。
基础设施层:
原版----本层做为其余层的支撑库存在。它提供了层间的通讯,实现对业务对象的持久化,包含对用户界面层的支撑库等做用。
补充----这层的职责包含了三层的数据访问,可是并不表明UI层就能够调用数据访问的代码,并且职责范围扩充了,有人可能会把它看成存放公用代码的地方,可是建议这里只存放本项目公用的东西,若是可以跨项目公用的代码应该放在一个叫作“应用程序框架”的项目来完成,每一个公司都应该有本身的应用程序框架。
回顾一下三层架构与DDD分层的区别:
a. UI层技术基本同样,一些比较智能的绑定可能没法进行了。
b. 服务层基本同样。
d. 业务实体+业务逻辑 = 领域层
e. 若是三层架构不采用业务实体与数据表一致的作法,这层也是同样。
2.2.2 DDD模式简单介绍
DDD的模式有:聚合,实体,值对象,工厂,资源库,模块。若是彻底没有DDD经验,建议首先阅读《领域驱动设计精简版》一书,可快速掌握DDD的理念。
聚合:这是个难点,通常建议是要设计小聚合,聚合与聚合之间用ID关联,不要直接引用。聚合包含实体,值对象。表达聚合的对象叫作聚合根。聚合内部全部对象的变动必须经过聚合根。聚合根的本质是一个实体。若是聚合要传递给其余模块(系统),通常不要直接传递聚合根,新建一个粗粒度的值对象来进行传递,即DTO对象,DTO也可由接收方创建,由接收方决定须要什么数据,这样就解耦了模块间的关联,至于数据库中是否须要把这个DTO冗余存储,则看实际状况。聚合的数据表设计原则:大表小类。即数据表采用粗粒度,聚合根内部使用细粒度对象,有可能的话,尽可能每一条数据表记录就是一个聚合。
实体:特色是必需要有一个ID来标识本身,可包含值对象和其余实体。
值对象:特色是个只读对象,没有ID标识。
工厂:因为聚合的建立多是个很是麻烦的事情,用工厂来封装这个复杂麻烦的过程。
资源库:资源库就是持久化聚合的地方,就是说数据存储的最小粒度是聚合。可是数据查询的需求可能很是灵活,实践中这条规则有点僵化,通常使用是读写分离方案,就是写的时候使用聚合对象,可是读的时候能够根据业务仔细创建一些查询模型(QueryModel)进行读取。至于数据库是否须要分红读写两个模型,仍是要看实际状况,在系统更复杂和须要更高性能的时候,数据库的模型也要分红两个,不过它们之间的同步就比较麻烦了。领域事件、CQRS、Event Sourcing等技术就是用来解决这个麻烦的。
领域服务:总有一些须要多个聚合进行合做才能完成的业务,它们不能简单地划归参与的其中一个聚合,要用一个领域服务来表达,注意领域服务不是应用层的服务。
模块:如何划分模块,通常有横向划分和纵向划分两种,横向划分例如:实体模块,工厂模块,资源库模块。纵向划分例如:商品模块,订单模块,支付模块,每一个模块内部都会具有聚合,资源库,值对象等元素。通常的经验是横向划分对项目没有什么帮助,纵向划分能够减小系统的复杂度。模块间的交互在应用层进行。
2.2.3 重构
掌握了DDD的知识以后,剩下的工做就是按照DDD的指导进行重构了。重构有风险,掌握成熟的重构手法能最大程度规避这种风险。在团队中进行改变架构级的重构,必须先要在整个团队中取得共识,不然你认为的改进在别人看来多是在改退。
在重构的过程当中,用各类代码坏味做为切入点,DDD模式、设计模式等做为方向,利用成熟的重构手法掌控重构过程,而后用SOLID设计原则评估你的重构成果。
最好团队中有比较精通须要掌握重构和DDD的人在旁指导和增强代码走查,确保一直走在正确的道路上。若是可以造成团队学习的氛围,那么一切都不重要了,如今没有掌握的思想技术,相信很快就能拥有。
再次强调,重构,是不少人的口头禅,可是他们不必定真的懂得什么是重构,没有掌握成熟的重构手法而进行重构跟盲目自信是一个道理,特别是对整个系统架构改进的重构,是个高风险的大工程,必须在团队中取得共识,并有明确的目的地和到达目的地的安全路径。
至此,三层到DDD的转换基本完成了,咱们主要完成了一个思想上的转变,今后咱们的技术之路踏上了新的征程。这是三层的终结,也是DDD的开端。路,还很长。
DDD的核心是要创建一个通用语言。何谓通用?首先项目全部关系人(需求、开发、测试、其余管理者、客户、甚至能够写到宣传海报上)都可以用通用语言来交流,人们要大声地建模,就是说领域模型应该可以容易地用天然语言表述,而后开发人员与计算机也要用通用语言交流,就是说尽可能把通用语言写进代码里面去,这就是所谓DDD的战略层面。通用意味着最接近事实,越贴近现实的结构就越稳定,而面向对象的特色就是要下降代码与现实世界的表示差别,这点和DDD是一致的,所以实现DDD的首选技术就是面向对象语言,固然Eric Evans最新研究认为用函数式编程也可以进行DDD。
面向对象的继承是一个最容易被误用的特性,通常认为组合优先于继承。更进一步,我认为基本上不该该经过继承来扩展对象的结构(属性),只应该用继承来区别行为(方法),这样作是符合里氏替换原则的。
创建对象结构是个很是复杂的工程,后面章节再介绍一点本人的经验。
延迟数据库实现
DDD让咱们把编程的核心从如何创建信息的存储结构,转移到如何让创建信息的事实结构上来了,这样,在陌生领域里一开始每每很难把握正确的结构,经过与领域专家持续地对业务的讨论,经过单元测试的反馈,经过重构慢慢将数据结构推向事实,到了项目后期,基本上不管需求发生什么变动,结构都是稳定的。在这个过程当中,对象结构的变化是至关激烈的,若是每次变化都要去修改数据表结构,也是一件很是麻烦的事情,所以若是在开发中可以把数据存储在内存中,而不须要去考虑数据库,将会大大提高开发的效率。可是要保持内存和持久化的查询接口一致是个麻烦事,每种ORM都有本身的查询语言,一旦你使用了某种ORM的查询语言,那么你就跟它绑定在一块儿了,若是想要换个ORM就难了,所以咱们或许应该考虑实现一个本身的不依赖任何ORM框架的查询语言。
取回只读属性
面向对象的重要特色之一是封装,这样会保护对象不被乱用,可是同时为重建数据结构带来了麻烦,不过如今的ORM基本都可以经过反射来取回只读属性了,还有个方法就是经过一个特殊的构造方法来取回数据结构。
对象属性递归引用
对象属性包含对象,这样无限的递归下去的状况,该如何存储?例如存储一个树的节点。这个时候必需要制造一个DTO来隔绝这种传递关系。
单个对象自己正确性验证
这种验证最简单,就是把三层里的验证方法搬进相关类里面就好了,可是若是客户忘记调用验证方法了,怎么办呢?咱们能够给全部须要验证的对象都实现一个验证接口(IValidatable),而后在保存入口自动调用此接口。
同类对象关键属性不能重复验证
因为咱们已经约定,领域对象尽可能不要跟数据存储打交道,因此要验证这个逻辑得放在服务层进行,可是这样的话验证方法的业务完整性就出问题了,所以把一个Repository传进检查方法也是一个办法,固然选择权在你团队的手上。
不一样类对象之间关系验证
此类验证参看上一条验证。
Talk is cheap. Show me the code. [Linus Torvalds]
说了那么多,不给些代码,小伙伴们都不一样意了,所以这个地址是本人的一个Repository的参考实现【仅供参考,责任自负】。
https://github.com/MurrayMol/MAF/tree/master/src/Repo
本实现的主要思想是以类型做为存储单位,用泛型减小Repository的接口,统一存储的入口方便规则验证,统一内存与持久化存储接口方便在不一样的存储结构中切换。
工欲善其事,必先利其器。思想再先进,最终还得以落地为准。为了实现上面介绍的思想,在本实现中用了三个开源软件,简单介绍一下:
ORM:Dapper,地址:https://github.com/StackExchange/dapper-dot-net
Dapper是个ORM框架,特色是须要写Sql语句,可能不少人会不喜欢这个。上面咱们提到了要推迟数据库的实现,可是不表明数据库的重要性也下降了,其实DDD强调的是提高曾经被忽略的数据结构(领域建模)的重要性,而不是贬低数据库的地位,数据库依然是第一序列的重要事物。对待如此重要的东西,我以为仍是写Sql语句才能表明咱们对它的尊重,并且面对一些查询模型,写Sql语句可以提供最强灵活性和最强的效率。至于Sql语句会变得很是复杂的问题,这绝对是你的数据模型没有建好,后面章节将会介绍一些数据建模的经验。
快速反射框架:Fasterflect,http://fasterflect.codeplex.com/
反射在框架设计是个不可缺乏的东西,可是它的效率是个不得不考虑的问题,Fasterflect是个使用Emit方式进行反射调用的框架,还有缓存、委托等方式提高性能。
OOM:ValueInjecter http://valueinjecter.codeplex.com/
相似于AutoMapper,EmitMapper等框架,不过这个框架的特色是提供了一个可容易扩展的转换接口(契约),它自己的转换类功能倒不是那么强大,不过配合Fasterflect使用将如虎添翼。
典型的三层架构开发过程:
三层架构以数据库为核心,首先根据需求创建数据模型,而后根据数据模型创建数据库,再根据数据表结构自动生成业务实体,而后能够同时进行业务逻辑及用户界面的开发。
一旦开发中业务有所变更,那么首先要修改数据库,从新生成实体,而后其余开发小朋友才能继续工做,网络链接很差、数据库挂机、数据库管理员未能及时更新数据库等等缘由都会致使开发过程被打断,好处是终于能够休息一会,坏处是因为要赶进度晚上可能得加班。
常常变动数据库结构总不是一件愉快的事情,为了不数据库结构变更,要求编码阶段以前尽可能要把需求固定下来,中后期越少变更越好。因为业务逻辑与数据库绑定紧密,因此单元测试困难重重。当性能出现问题的时候,究竟是代码逻辑没有写好,仍是Sql语句没有写好,诊断有点困难。因为类的粒度太大,设计模式罕有用武之地,设计原则跟本身没有关系,长此以往可能会以为编程思想都是骗人的。
DDD开发过程:
DDD以领域模型为核心,首先根据需求创建领域模型,而后根据领域模型创建代码模型,而后就能够同时开发业务逻辑和用户界面了。
咱们有一个模拟数据库存储接口的内存数据库,所以这时候不须要考虑数据库,若是这时业务发生变化,直接修改对象结构是很是简单的事情。直到开发后期,全部功能都已经开发完成,业务结构也稳定下来了,咱们再根据领域模型创建数据库,进行一个简单的与业务逻辑集成就完工了。
免除了开发过程当中数据库常常变更的烦恼,开发过程不会被打断,随时能够进行单元测试,随意能够与用户界面集成把系统跑起来,开发逻辑的时候不考虑数据库,开发数据库的时候不考虑业务,关注点更加集中了。出现性能问题能够单独测试数据库组件和业务逻辑组件,更容易定位问题。类的粒度很小,各类重用,各类设计思想都纷纷派上用场,感受终于跟国际接轨了。
Comming Soon....
Comming Soon....
Comming...
Comming....