如何通过高内聚低耦合 例子消除Bug

jooq 入门_jooq_壮志凌云
以下内容已过滤百度推广
jooq, a fluent api for typesafe sql query csnotruction and execution....
jooq lets you hook into its sql generation l...&&普通
best practices and lesssno learned from writing awesome java and sql code. get some hands-on insight on what's behind developing jooq.&&普通
java object oriented querying, commonly known as jooq, is a light database-mapping software library in java that implements the active record pattern...&&普通
jooq is an innovative solution for a better integration of java applicatisno with popular databases like oracle, microsoft sql server, ibm db2, or sap ...&&普通
joor - fluent reflection in java joor is a very simple fluent api that gives access to your java class structures in a more intuitive way. the jdk'...&&普通
jooλ is part of the jooq series (along with jooq, joox, joor, joou) providing some useful extensisno to java 8 lambdas...&&普通
introduction i accidentally stumbled onto jooq a few days ago while doing a lot of research on hibernate. funny how things work, isn’t it? for those...&&普通
java object oriented querying (jooq) explained by example using intellij idea 13.&&普通
this category contains posts related to current developments of jooq... may 9, 2016may 9, 2016 jooq-development, java, java 8 leave a comment annotatioma...&&普通
语义关联近似词猜&正规性45地理位置网址标题|网址|摘要F0略略分类信息&|&猜&非正规中略略略精确匹配1略略分类信息&|&猜&非正规中略略略精确匹配3略略分类信息&|&猜&非正规中略略略精确匹配4略略分类信息&|&猜&非正规中略略略精确匹配5略略分类信息&|&猜&非正规中略略略精确匹配6略略分类信息&|&猜&非正规中略略略精确匹配7略略分类信息&|&猜&非正规中略略略精确匹配8略略分类信息&|&猜&非正规中略略略精确匹配9略略分类信息&|&猜&非正规中略略略精确匹配10
12时间限制猜&实时动态5相关检索词泛时效性8F1略略略略略略略略1略略略略略略略略3略略略略略略略略4略略略略略略略略5略略略略略略略略6略略略略略略略略7略略略略略略略略8略略略略略略略略9略略略略略略略略10
url2345摘要前标题后标题F2略略略略略元描述略1略略略略略略略3略略略略略正文略4搜索结果与查询词广度相关略8略略略略5略略8略略略略6略略略略略正文略7搜索结果与查询词广度相关略略略略略略8略略略略略略略9略略略略略元描述略10
123原创猜&网址形式6相关词猜&相似度F3略略略略主页次优先&|&子页内容充实略略精确匹配1略略略略主页次优先&|&子页内容充实略略精确匹配3略略略略主页次优先&|&子页内容充实略略精确匹配4略略略略子页优先级较低略略精确匹配5略略略略子页优先级较低略略精确匹配6略略略略子页优先级较低略略精确匹配7略略略略子页优先级较低略略精确匹配8略略略略子页优先级较低略略精确匹配9略略略略子页优先级较低略略精确匹配10温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
我,一个名不见经传的黑毛小子,一个曾经壮志雄心的不怕虎的初生牛犊。00现在的我,有精力,有时间去创造我的未来,我还在努力,还在奋斗!~~~
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
阅读(636)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_080066',
blogTitle:'《代码之道》精华',
blogAbstract:'& \r\n一、项目的不当管理\r\n1)&&&&&&& 软件工程绝对是含糊的。\r\n2)&&&&&&& 相信一半你看到的,别信你听到的。\r\n3)&&&&&&& 这不是个人的事情。\r\n4)&&&&&&& 分诊的5条黄金法则:光上门;所有的决定都是团队决定;每个工种只派一名代表;指定一个可以做最终决定的人;所有的决定都应该是“贵格会教徒”的一致意见。\r\n5)&&&&&&& 魔鬼藏在细节里面。\r\n6)&&&&&&& “银弹”游戏规则:你在任何时候都可以用银弹来获取特权,让大家遵从你的意见,但是子弹用掉一颗就少一颗,用完为止。\r\n7)&&&&&&& 管理层非常的愚蠢;管理层天真得难以置信;管理层不切实际;管理层没有良心、不负责任;管理层都是些毫无责任感的懦夫。(死亡行军)',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:0,
publishTime:6,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'我,一个名不见经传的黑毛小子,一个曾经壮志雄心的不怕虎的初生牛犊。00现在的我,有精力,有时间去创造我的未来,我还在努力,还在奋斗!~~~',
hmcon:'1',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}谁在害怕大的复杂类? - ImportNew
作为软件领域的黑洞,大规模的类往往导致一些不好的反馈:这些类增长的如此迅速,使得程序员害怕他们,而不得不只是简单地加一些功能到里面,这也导致了下一个程序员做出同样的选择。所有人都知道这些类应该被销毁,将他们的功能分散到一个个更小的类中,但是没人知道从哪开始。哪一个方法应该被最先移出?做出这个决定的依据是什么?有什么准则可以遵循?
Fowler在他的书中这样写道:
“如果我不确定是否应该移动一个方法,我就去看看其他方法。移动其他方法通常比较容易决定。不过有时还是很难下决定,但这也没什么大不了的。如果决定很难下,就说明了怎么选择都可以。然后我就根据直觉来做;再者,我还能在以后改变决定。”
这个真的比一些客观技术标准更有帮助。
下图展示了一个图。图中每个圆点代表一个方法,一条线表示SequenceDiagram类中的一个依赖。
图1:SequenceDiagram类
这个类增长的很大,需要将其中的一些功能移动到一个新的类中。一个程序员应该从哪开始搜索需要移动的方法?可以考虑下面四个条件:
重构的目的是求取供体类和新类之间的某种平衡。如果只是将供体类的大部分方法移动到新类,似乎没什么作用。因为这只是将复杂性从一个类移动到另一个,没解决任何问题。
新类自身应该具有完整性。不应该是随机选择一些方法或没联系的方法移动到新类:它的方法必须服务于一些共同的目的。共享依赖提供了一个很强的共享职责,通过从供体类中选择一些已经合作过的方法来使得新类形成一个内部依赖的整体,实现一个最好实现的功能。所以程序员不是随意挑选一些方法,而是移动一些有关联的方法。
任何候选方法的结合都将对系统其他部分产生影响。现代的工具和IDE能最大程度简化方法移动的操作,但是只有程序员才能从设计层面避免不恰当的移动;就像新类必须享受完整性,但也必须供体类因此而引发的不完整性。从候选集中选择方法的个数反映了由重构引起的不完整性的程度。在做出选择时应该慎重考虑这个数字。
有了这三项标准(第四项在后面会给出),程序员就能系统和客观的搜索方法。这些准则不保证能给出解决方案,但是他们至少避免了过早地放弃寻找优化办法。在下图中,被影响的集合将被审查(一个被影响的集合是那些从某些特定方法能够到达的方法)。每一个方法的圆点根据以下原则被标记为红色:一个深红色圆点表示该方法的孩子节点(和孙子节点…)被很多其他方法依赖,不适合移动。暗红色圆点表示该方法的后继节点很少被依赖,建议移出。黑色节点表示少于两个方法依赖。
在下图中,程序员点击execute()方法来高亮显示它的影响集合,然后会发现只有5个其他方法依赖于该集合中的元素。
图2:可以移动的节点太多
上面的选择会因为规则1而失败:移动大量方法到新类,使得新类和供体类一样庞大和复杂。然后进一步探索,点击下图中的drawDiagram()。
图3:可以移动的节点还是太多
不幸的是,和上面情况一样,drawDiagram()方法的影响集合太大,以至于不能在新类和供体类之间找到一个平衡,所以否定了该方案。下面来点击drawClassLines()方法,见下图。
图4:可以移动的节点太多碰撞
现在,需要移动的方法集合看起来应该不太大也不太小。这种选择体现在工具中就是:12个其他方法依赖于这个集合中的一些方法,那些深红色的圆点就是个警告。下图所示的搜索过程是点击drawLineFromCallingToCalled()方法的结果。
图5:可以移动的节点比较合适
成功。这个选择提供了一个由6个方法组成的集合,他们都有一个共同的祖先,也就是这6个方法是相互依赖的。这在集合规模上是个很好的选择,并且对第一次重构很有帮助。下图则展示了重构的过程,6个方法中的每一个都从SequenceDiagram类中移出。
图6:移动6个方法
这一次重构后,SequenceDiagram类如下图所示。
图7:第一次重构结果
注意到一些额外的方法被添加到第一行:这些都是允许新类能够访问的SequenceDiagram类的一些数据;这些方法都将提取出来作为一个接口,以避免循环依赖。它们只是给供体类增加了一点复杂性,所以该方案可行。下图展示了新类CallingLine和它的新“用户”。
图8:产生一个新类CallingLine
当然,这项工作还没有结束。尽管刚才成功提取出了一个新类,供体类还是很笨重,需要继续移出一些方法集合。这里,第4项也是最后一项标准是:深度。好的设计要求尽可能小的传递依赖。研究图7会发现,两个新方法集合会非常明显:它们在图形的最下面非常显眼,它们是最深的可到达方法。图9展示了positionOwningSetNameBoxes()的影响集合。
图9:继续探索一个新的候选方法
图10展示了第二个方法stripeBackground()。
图10:继续探索第二个候选方法
尽管影响集合没有变得更大,这两个方法只被另外4个方法依赖,所以它们的关系基本没有变化。图11展示了被SequenceDiagram类影响的两个集合的移出过程。注意在这个操作中,图形深度的降低。
图11:移出另外7个方法
第二次重构后的SequenceDiagram类如图12所示。
图12:第二次重构后的SequenceDiagram类
最后,研究图12的结构发现的另一个可移出集合:processOwningSetNamesPrinting()方法的影响集合,见图13。
图13:最后一次试探
这个方法集合尽管很小,但是扩展依赖到了新创建的类,使得它更像是新类中的一部分。图14展示了这三个方法的移动过程。
图14:移动最后3个方法
图15展示了最后的结果,重构的SequenceDiagram类,它相对独立,更容易从依赖关系上理解其独立性。
图15:类SequenceDiagram
图16是重构之前的类,比较下它们的区别。
图16:原始SequenceDiagram类
图17展示了新类CallingLine的最终形式,它在结构上并不复杂。
图17:类CallingLine
害怕是因为缺乏经验。
一些程序员害怕重构复杂类仅仅是因为他们不知道从哪开始。有的程序员知道:不管一个类有多复杂,通过不断地应用一些简单的规则,能帮助阐明整个过程(这一方法也适用于包)。这些人慢慢学会了如何去解决这类问题,找出隐藏在系统中的复杂类,通过把这些类一点点减小来寻找乐趣。
原文链接:
- 译文链接: [ 转载请保留原文出处、译者和译文链接。]
关于作者:
java码农一枚,兼顾DB和algorithm
很不错的文章
关于ImportNew
ImportNew 专注于 Java 技术分享。于日 11:11正式上线。是的,这是一个很特别的时刻 :)
ImportNew 由两个 Java 关键字 import 和 new 组成,意指:Java 开发者学习新知识的网站。 import 可认为是学习和吸收, new 则可认为是新知识、新技术圈子和新朋友……
新浪微博:
推荐微信号
反馈建议:@
广告与商务合作QQ:
– 好的话题、有启发的回复、值得信赖的圈子
– 写了文章?看干货?去头条!
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 活跃 & 专业的翻译小组
– 国内外的精选博客文章
– UI,网页,交互和用户体验
– JavaScript, HTML5, CSS
– 专注Android技术分享
– 专注iOS技术分享
– 专注Java技术分享
– 专注Python技术分享
& 2016 ImportNew966,690 八月 独立访问用户
语言 & 开发
架构 & 设计
文化 & 方法
您目前处于:
架构漫谈(八):从架构的角度看如何写好代码
架构漫谈(八):从架构的角度看如何写好代码
被首富的“一个亿”刷屏?不如定个小目标,先把握住的优惠吧!
相关厂商内容
相关赞助商
QCon全球软件开发大会上海站,日-22日,上海宝华万豪酒店,!
在第六篇文章中,我们得出一个结论,软件架构实际上包括了:代码架构,以及承载代码运行的硬件部署架构。实际上,硬件部署架构最终还是由代码的架构来决定。因为代码架构不合理,是无法把一个运行单元分拆出多个来的,那么硬件架构能分拆的就非常的有限,整个系统最终很难长的更大。
所以我们经常会听说,重写代码,推翻原有架构,重新设计等等说法,来说明架构的进化。这实际上就是当初为了完成任务,没有充分思考所带来的后果。这也并不是架构进化的事情,而是个人对问题领域的逐渐深入理解的过程。所以有必要再讨论一下,代码的架构应该是怎样的。
本文会在之前几篇文章的基础上,进一步探讨如何把架构的思考进行落地,细化到我们代码的实践当中,尽量不要让代码成为系统长大的瓶颈,降低架构分拆的成本。
在前面我们提到,软件实际上是对现实生活的模拟,虚拟化。这是一个非常重要的前提,直接决定了我们的代码应该分为几部分。结合每个部署单元所承担的责任,可以明确的拆分为两个不同的责任:
表达业务逻辑的代码。很多人把这部分叫做Domain Logic,或者叫Domain Model。这部分实际是来源于生活的,必须保持和现实生活中的切分一致,并非人为的抽象而成。
对用户提供访问并保存业务逻辑运行结果的代码。计算机的状态保存有一个缺陷,本机保留业务运行结果有很大的问题,一般都在外存储设备上保存,也便于扩展。
所以单个部署单元的代码可以分为两个部分,如下图所示:
(点击放大图像)
从这个图中可以看出,软件代码的相关利益人为运行时的访问人员和存储设备。而service的代码是最复杂的,需要服务于三方,代码人员的负担是最重的。为了把这三方的变化对service的影响降到最低,对于service还必须进一步的分拆为三个部分,让每一个部分都能够独立的变化,这样这三方的变化就不会产生连锁响应,降低成本。如下图所示:
(点击放大图像)
这样,就划分成了几个责任:
Service就专注于user的需求,并组合Glue Code提供的服务完成需求。
Glue Code专注于组合business的调用,管理Business里面对象的生命周期,并且通过Repository保存或加载Business的状态
Business专注于实现业务的核心模型。
Repository专注于数据的保存,并和存储设备一一对应。
大家注意看,还是树形架构。并且左侧的主要需要计算机的相关理论知识,并且要直接面对用户的需求。右侧的更多的需要面对业务的核心。只要这几块的开发人员互相商量好了接口定义,这几个部分的开发就可以并行的进行,极大的提升开发的效率,缩短开发的时间。要做好这几部分,还需要注意,逻辑只允许存在于Business中,Service、Glue Code、Repository都不允许存在业务逻辑。为什么呢?首先我们来看看什么叫业务逻辑。
什么叫业务逻辑?
首先这个定义的前提是指软件代码中的逻辑,不是现实生活中的逻辑。在软件代码中,不需缩进和计算的顺序调用,包括缩进的代码目的是catch exception的,都不算逻辑,除此以外都是逻辑。以下用严格的顺序调用来指代这种代码。因为顺序调用是计算机的特性,由编译器来决定的,当然最本质的是因为我们计算的基础都是图灵机。在现实生活中,顺序调用也是逻辑,大家不要和我们这里说的业务逻辑相混淆。
为什么说除了Business代码中有逻辑以外,其他地方不能有逻辑呢? 我们每个部分分别分析:
如果service里面不是严格的顺序调用,有很多分支,那么说明这个service做了两件或者两件以上的事情。必须把这个service分拆,确保每个service只做一件事情。因为如果不这么分拆的话,一旦这个service中的某各部分发生变动,其他的部分的执行必定会受影响。而确定到底有哪些影响的沟通成本非常高,其他相关利益方没有动力去配合,我们往往不会投入精力仔细评估。最后上线会出很多不可预料的问题,最终会导致损失用户的利益,并且肯定会导致返工,损坏自己的利益。如果是有计算的逻辑的话,比如受益计算,订单金额计算等,那么这部分应该是Business代码需要完成的,不能交给service代码来实现。
Glue Code里面如果不是严格的顺序调用,同理会和service一样遇到同样的问题。
Repository里面如果不是严格的顺序调用,包括存储访问的代码里面(比如SQL),会导致逻辑进入到存储设备中。存储设备的主要目的是拿来存储的,一旦变成了逻辑计算的主体,就会导致存储设备无法通过增加机器的方式横向扩展长大。这个时候就没有架构了,只能换性能更好的机器,这个叫scale up。只有scale out才能算架构。
以上都会导致架构无法快速的横向扩展和分拆,并且增加了修改的成本,这些是不符合开发人员以及业务的利益的。
这么做的好处有哪些呢?
Service、Glue Code、Repository里面的代码是严格的顺序调用,那么这些代码只要做连通性测试即可,不需要单元测试。因为这些代码都需要和很多上下文打交道,很难做单元测试。这样才算是真正的组合。
Business不访问任何上下文,不访问任何具体的设备,所以这部分代码是非常容易些单元测试的,并且单元测试必须100%覆盖。因为其他地方没有业务逻辑,所以一旦有问题,就可以断定是Model的问题,单元测试肯定可以发现。如果单元测试没有发现问题,那么单元测试一定有问题。线上问题的模拟也就变得非常的简单,单元测试也能够得到进一步的补充。
Repository很容易按照存储设备本身的最小访问粒度来完成工作,比如DB,完全可以做到单表访问。因为这个时候存储设备只关心存取数据,完全和业务没有关系。做表的分拆也是非常容易的事情,存储设备通过增加机器就可以横向扩展长大。很多人会担心说,没有了join,访问DB的次数是不是更多了,会导致性能下降? 按照现在网络的条件,网络访问和Disk IO访问的差距已经不大了,合理的设计下,多访问几次DB并不会导致这个问题。另外如果多台DB的话,还能通过并行加速访问。
由于Service、Glue Code、Repository代码简单了,才可以让我们的开发人员投入更多的时间研究业务,毕竟这部分才是软件所真正服务的对象。
我们再来看一个实际的例子,如下图所示:
(点击放大图像)
Manager类实际就是Glue Code。有几个注意点需要说明一下:
不能把Business Model当做数据对象来处理,Model关心的实际上是业务行为,数据只是是这些行为的结果。所以Glue Code需要把Model转换为Entity,Entity和存储设备里面的存储粒度一一对应。比如在DB中,每个Entity对应一张表,并且跟着表的变化而变化,这样就保证存储的变更不会影响Model。同样Service和用户之间的数据交互,也是不会和Model之间相关的,确保用户的需求变化,不会影响到Model。因为用户的需求变化是最频繁的,没有逻辑,可以让我快速的满足业务的需求。
在Service这里,最好不要考虑代码重用。因为当多个不同的角色访问同一个接口,一旦某个角色的需求发生了变化,就会要求开发人员去修改。而这个修改往往会影响到其他的角色,需要这些角色一起配合来确定是否受影响,但是这些角色因为没有需求,往往不会配合。这样就给开发人员造成了很多不必要的沟通,成本是非常高的。最终都会导致线上Bug,影响最终的用户。所以尽量给不同的角色不同的Service,避免重用,降低沟通成本。很多人会说这样Service不就太多了吗? 这样Service注册,查找等管理需求就出现了,Service治理中心就是来解决这个问题的。因为Service里面没有逻辑,所以开发和管理非常的简单,可以快速应对业务的变化。我们只有更快地变,更容易的变,才能更好地应对变。
Business Model是必须要重用的,一旦发现重用出现问题,那么说明Business Model的识别出现了问题,这是一个我们要重新思考Model的信号。Business Model必须是一个完美的树状,如果不是,也说明Model的识别出了问题。
在实际操作中,Service、Glue Code、Repository不能有逻辑,实际上和很多人的观念是冲突的,认为这个根本做不到。做到这一点需要很多的学习成本,但是一定可以做得到。当发现做不到的时候,可以断定是业务的分析出了问题。比如不该合并的合并了,不该计算的计算了。这个问题一定有办法解决的,做不到都是理由,无非是想早点把自己的工作结束罢了。虽然刚开始会比较困难,一旦把这个观念变成自觉,开发的质量和效率马上就能高好几个级别。
我的游泳教练曾和我说过这些话,我至今记忆犹新:&业余选手,越想从水里浮起来,就越想把头抬起来,身体反而沉下去。只有克服恐惧,把头往水里压下去,身体才能够从水里浮起来。真正专业的习惯往往是和我们日常的行为相反的&。
我们真正想快速的完成代码工作,就要克服自己对时间的恐惧,真正的去研究业务的问题,相关stakeholder的利益,把这个变成我们的习惯。写代码的时候让该出现逻辑的地方出现逻辑,让不该出现的地方不能出现。一旦不该出现的地方出现了逻辑,那么要马上意识到,这个地方是一个坑,这个问题一定和业务的分析不透彻有关系。
很多人可能会把这个做法和Martin Fowler曾经提出过充血模型和贫血模型来比较,和Domain Driven Design来比较,其实没有必要。这个分拆完全是从软件所解决的问题,根据软件架构推导出来的,很多地方和两位前辈的观点是一致的,但是并不完全等同。
以上只是针对单一的Service部署单元的分析,扩展开去,对于其他的部署单元也是类似的。每个单元的下一级都可以认为是Repository,每个单元的上一级都可以认为是User。这些实践在我自己的项目中都有用到,非常的有效,迭代的速度非常的快。很多人担心Business Model建不好,其实没关系,刚开始可以粗糙一点,后续可以慢慢的完善。这个架构已经隔离好了每个部分的变化对其他部分的影响,变化成本都在可控的范围之内。
感谢对本文的策划和审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至。也欢迎大家通过新浪微博(,),微信(微信号:)关注我们。
Author Contacted
告诉我们您的想法
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
架构和代码的联系: 直接映射
依情况而定
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
赞助商链接
InfoQ每周精要
通过个性化定制的新闻邮件、RSS Feeds和InfoQ业界邮件通知,保持您对感兴趣的社区内容的时刻关注。
架构 & 设计
文化 & 方法
<及所有内容,版权所有 &#169;
C4Media Inc.
服务器由 提供, 我们最信赖的ISP伙伴。
北京创新网媒广告有限公司
京ICP备号-7
注意:如果要修改您的邮箱,我们将会发送确认邮件到您原来的邮箱。
使用现有的公司名称
修改公司名称为:
公司性质:
使用现有的公司性质
修改公司性质为:
使用现有的公司规模
修改公司规模为:
使用现在的国家
使用现在的省份
Subscribe to our newsletter?
Subscribe to our industry email notices?
We notice you’re using an ad blocker
We understand why you use ad blockers. However to keep InfoQ free we need your support. InfoQ will not provide your data to third parties without individual opt-in consent. We only work with advertisers relevant to our readers. Please consider whitelisting us.}

我要回帖

更多关于 高内聚低耦合原则 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信