阅读更多
接口是软件工程最重要的概念,在java上要格外感谢Spring的贡献。
这个概念对于新人来讲,是比较难理解的,最重要的原因就是需要有一定的代码量,特别是做过一些项目的重构,维护,变更等事情的时候感触才会更深一些。
1 “接口+实现”最常见的优势就是实现类和接口分离,在更换实现类的时候,不用更换接口功能。
比较常见的例子是发送短信。
一般发送短信的场景包括注册用户,找回密码,重要通知,修改交易密码等。
短信现在的结构是先接上各家短信通道公司,再经由联通移动等发送出去。
一般而言,短信分成两种,一种注册短信,一次只发给用户一条。这种短信到达率比较高,可能会在99%以上,也要看各种短信通道方,更会区分移动和联通。
另外一种是营销短信,这种短信常见于“某公司3周年大庆,1元领取程序员鼓励师”之类的。
这种短信到达率非常低。而且也经常会被封掉。
但是短信又是注册的第一步,用户体验做的再好,手机收不到验证码也没用。
所以觉见的做法是,会备用两个或者是多个短信通道。
刚刚已经讲过了,调用短信接口的地方比较多,可能是用户发起的,也可能是程序检测到某种行为触发的。
也就是说,会有多个地方调用短信接口,那么我们这个时候要解决的问题就是,能否在更换短信通道方的时候,不更改其他模块中被引入的代码?
接口在这个时候就完美的实现了这个功能点。无论是哪个模块,我要发送的内容和预期的结果是一致的,具体是用哪家短信通道的实现类,不重要。
所以通常是一个SMSService做为接口,不同的公司因为有不同的实现方式,所以会有多个实现类,比如说SMSService{CorpA}Impl,SMSService{CorpB}Impl。
这是一个完美的抽象,无论未来有多少种短信公司接入,无论短信公司的营销人员送了多少个香吻给公司的商务总监,程序员总是能够开心的完成功能。
2.这对于做单元测试也非常有帮助。
如果你是一个有了那么点经验的程序员,如果你还没有习惯TDD的开发。可以体验一下这种写法。还是拿短信为例。
先写一个SMSServiceTest。
然后写一个Test方法。
这个时候什么都没有,不用管。先直接这么写。
int code=SMSSevice.sendTextMessage(mobile,content,type);
这个时候IDE会提示你没有这个SMSService,用代码自动生成工具去创建这么一个接口出来。
再根据提示把方法创建出来。
再写 SMSService smsService=new SMSServiceCorpaImpl();
再根据代码把实现类生成了。一般来说IDE会自动留一个空的方法。不用管。
这里只是一个简单的例子,但是你发现,当你用TDD的这种方式去写代码的时候,完全不用关系SMSService是怎么内部实现的。
你只需要继续写你的单元测试代码好了,明确的知道这个SMSService要做的功能是发送短信,需要传递手机号,内容,类型,返回一个状态码。
那么接着说为什么对单元测试很方便?
一般而言会用Spring配置Bean,所以实际上你的单元测试代码也不用有改动,无论是测试哪一个实现类,都只通过更改配置文件就可以完成。
想想,如果没有接口呢?
是不是要对每一个短信通道单独写一个单元测试的方法?
3.对于不需要频繁更变实现类的方法,是不是就可以不用写接口了?
答案是No。整个系统架构的代码可以单纯认为有四部分构成。Model+Interface+Service+Util
Model是纯粹的Pojo,贫血模型,Inteface和Service是接口和实现分开的,Util是全项目通用,或者是跨项目通用的,跟业务逻辑没有任何关系的。
写接口最大的好处就是在你写的Controller代码,或者是Service里的主要业务逻辑代码的时候,屏蔽掉细节。
写一个业务逻辑的时候,比如说修真院的加入班级。
第一步,做校验,用户是否为空,班级是否不存在,是否已经加入了班级等等。
第二步,更新班级和用户的关系表,更新班级总人数,更新职业总人数,更新用户的最新班级ID。
第三步,发送系统通知,告知用户加入班级成功。
如果说不用接口,只用实现类的话,第一种方式就是把所有的代码都写在这个Controller里去,代码会非常非常繁琐,一个函数突破几千行轻轻松松,而且改动起来很麻烦。
第二种方式就是抽象出来函数。这种方式在某种程度上能够解决代码块大的问题,但是你必须要New一个实现类出来,想想在上述逻辑中,需要new几个实现类?
这些实现类就会被New的各处都是,甚至改个名字都很蛋疼。
但是如果你使用接口的话,你会发现,接口是强制于你去将复杂的业务逻辑抽象成具体做的事儿。
比如说,
if(user==null){
// to do something
}
就变成了CheckUser(uid)这么一个接口。实现类也明确了自已要做的事情。
从某种程度上来说,抽象成一个私有方法也能解决这个问题,但是一般都会推荐,如果你发现你写了很多私有方法,要么是他们可以继续演化成一个util,要么是可以成为一个Service。
嗯,说的有点乱。