首页 存档 技术 查看内容

设计模式-搞个接口,留有余地,让你我不再尴尬

2018-3-30 13:00 |来自: 互联网 330 0

摘要: 设计模式,Design Patterns,Pattern,翻译为“模式”总感觉不够接地气,用今天的话来说可以叫“套路”。设计模式就是写代码的过程中一些常规打法和套路。只不过被列入GOF的套路是那些大牛们巨人们在长期的生产劳动 ...

设计模式,Design Patterns,Pattern,翻译为“模式”总感觉不够接地气,用今天的话来说可以叫“套路”。设计模式就是写代码的过程中一些常规打法和套路。只不过被列入GOF的套路是那些大牛们巨人们在长期的生产劳动中总结出来的公认的并且能解决一大部分人的就业问题的最佳实践。


这些年来,民间流传着一种说法就是 “模式无用论”。就是认为设计模式没什么鸟用。 由于本人资历尚浅,也不知道对不对。但每每听到这些话的时候,我就在想,spring很多人都说好,他不就是用了一个个设计模式架构起来的吗?


这里就不拿冷饮店的生产流程来讲解模板模式或者装饰者模式了。我就把我在写代码过程中遇到的一些设计模式的内容分享给大家。


在分享这些之前,我们还是来回顾下设计模式的基本内容吧。


你肯定看到过很多的设计模式的书籍,一般都会分别介绍每一种模式,而且把每种模式的内部细节一一对比和分析,来强化每种模式一定要有的样子。


但你也许也发现了,就是有很多模式其实都长得差不多。没错,其实设计模式就是围绕着java的面向对象和java语言本身有的特性做各种闪转腾挪,从而优雅的解决一些实际开发中的一些问题。


别看,GOF列了那么多,其实可大体分三类:


创建型


这一类就是围绕着怎么new出来一个对象而不遗余力,各种姿势的new对象。


行为型


这一类,核心的就是使用interface来搞,所以你看到很多是设计模式都离不开搞个接口。


结构型


这一类设计模式,就是围绕着,怎么把类和类进行组合,配合,组装。


既然是套路,肯定就是能给我带来很多好处。比如你玩耍王者农药,比如玩亚瑟的套路就是先去适当打野,好有个大,然后再去砍杀。这就是套路。


回到设计模式。我认为设计模式的核心追求就是 整个架构的可持续性。或者更直白的讲就是如何更好的应对变化。再往外说就是:面对新的需求,我们能够以更优雅的姿势 回答 需求提出者 的问题。


可持续性主要有两层意思:

1、一层意思是如果出现问题,需要回溯我可以优雅支持。

2、一层意思是如果来了新的需求,我可以优雅的应对。


如果解决了上面两个诉求,我想,这个事情就应该是可持续的。


接下来我就列举几个在我开发工作中遇到的几个比较典型的工厂模式的例子。


案例一、多缓存支持


一个是我们在开发缓存组件的cilent的时候,需要支持同一应用下支持多个缓存实例的同时存在。比如我同时可以使用redis和ehcache。那么这时候我就希望他们在项目启动时一次性全部实例化好,然后存在一个map中。这样的话,我就可以在使用缓存的业务方法上加缓存注解,然后指定对应的缓存实例ID,然后使用这个缓存实例进行存取操作,如果想使用另一种缓存,则只需要修改实例ID就可以了。


案例二、多通知渠道支持


还有最近我们在做一个监控告警中心。里边需要支持邮件、短信、电话语音、微信等多种通知渠道。而每个通知方式的实现逻辑是不一样的。那么这时候我就希望这些逻辑开发者可以自定义。然后在应用启动时一次性初始化好自定义的这些实例,然后保存到map中。在真正需要用这些逻辑的时候再通过getChannnel的方式获取对应的逻辑。由于在具体getChannel的时候我并不知道具体实现,所以只能基于接口来抽象。


案例三、WebMvc URL-Mapping


还有之前我自己尝试过去写一个简单的webserver。其实就是我们经常用到的controller那一层的映射。就是在应用启动时自动扫描所有含有microservice注解的类,然后实例化好以后,然后把注解上的URL mapping作为key,当前类对象作为value存入map。这样就完成了URLmapping。然后在具体的httpserver的总handler中根据request请求的URL来去map中寻找还URL对应的handler实现。当然这里的map是被封装到一个context中的。你可以认为这个就是那个XXXFactory。没错,包括spring的webmvc也是这么实现的。


其实你发现在我们的开发过程中除了我们使用的那些开源框架在用factory pattern。在我们自己的开发中也经常需要用到工厂模式,而且适当的使用该模式也能解决我们像上面一样的问题。


核心就是基于接口然后加个map。这就是工厂模式的核心。


使用接口,让在遇到新的需求时候,不用去修改你写好的核心代码。因为你的核心代码都是接口。你只需要基于指定的接口编写新的实现就可以了。你发现没?你并没有修改一行代码。只是单独增加了一个实现类,然后一切就优雅满足。这不就是我们经常说的那句:面向修改关闭,面向扩展开放吗。至少对于我自己来说,能不改代码就不改。为了“不改”这个目标,我会想尽一切办法来完成这一目标,比如我总是会用接口;还有有时候在向前端push一个具体的满足UI的数据entity,为了不修改dao层的entity,我甚至会在自己的业务类中写一个私有的entity然后继承现有的dao的entity,然后添加一些属性,总之我就是不喜欢修改现有代码,我总是喜欢扩展。


原因很简单,我扩展的属性只有这一处用到,如果基于dao entity来添加属性,对于其他场景来说,这一个并不通用的属性就是一个累赘和负担。


而且修改现有代码总有种隐隐的不安,而且我新建一个类似乎要安全很多。这样的话,即使我新的代码出现问题了,我也可以快速的回退(或者叫回滚)到之前的实现中去。有时候设计模式在茫茫的代码中会充当着像版本管理软件一样的角色。它让你在具体的代码实现内部可以保留之前版本的代码,如果想要升级只是基于原有的代码文件进行扩展和覆盖就可以了。而不需要基于之前的代码来硬修改。


说到修改,还有一个小故事分享,一天某部门的A来找我说,缓存组件的使用的序列化方式不满足它们的需求,问我能不能修改。然后我告诉他,缓存组件默认的序列化实现是基于kyro的,如果你觉得不满足你的需求,你可以自定义自己的序列化实现,然后配置就是了。


你想想如果当初没有基于接口来做,那么这时候我只能告诉那位哥们说那你没法使用了。再想的极端一点,如果默认的序列化实现有bug,恰好在他所在的场景下出现问题了。如果当初没有用接口来抽象,估计这会我已经在仓促的开始修改实现了,然后仓皇的去走流程发布新版本了。


这种仓皇失措显然已经露出了不可持续的端倪。长此以往,代码的质量能够保证吗?


留个接口,留有余地,彼此都不至于太尴尬!


接下来我们再回顾下工厂模式的典型代码吧:


总是得先有个接口:


public interface Shape {
void draw();
}


然后是两个不同的实现:


public class Rectangle implements Shape {
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}


public class Circle implements Shape {
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}


然后就是XXXFactory上阵了:


public class ShapeFactory {
final static Map
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部