什么是框架?

想起当初学习 Java 和 Android 开发的时候最后一个没有迈过去的门槛就是框架了。一开始我还很纳闷什么是框架,后来学习的时间长了才慢慢理解这个概念。同样,我们今天来看看码农翻身公众号的文章,该文章是以一个故事的形式来展开,极其有趣。通过这个故事来深入理解一下什么是框架


来源:码农翻身 微信公众号

作者:刘欣

原文地址:码农翻身-一个故事讲完https

码农菜鸟张大胖立志走上Java之路, 听了大神Bill的指点, 先学了Java SE, 把集合、线程、反射、IO、泛型、注解之类的基础知识学了一遍, 在Bill的严厉督促下,写了大量的代码。

然后开始学Web基础,什么Http, html, javascript , css , servlet, jsp , tomcat …… 又是一大堆知识点。 他在网上找了一个小网站, 自己模拟着做了一下, 虽然不是专业美工, 界面惨不忍睹, 但总算是把功能模仿了七七八八, 很有成就感。

大胖拿去给Bill 看了, Bill 夸奖道: “嗯,功能实现的还可以, 没有用任何框架能做成这样子, 很不错。 ”

大胖说: “框架? 什么是框架?”

Bill 愣了一下: “ 你还突然把我给问住了, 我们整天开口框架,闭口框架, 现在让我给框架下个定义, 我还真说不出来, 让我想想。 ”

Bill 闭目养神, 大胖虔诚等待。

不到一炷香功夫, Bill睁开眼睛:“ 我来给你举个例子, 你不是刚刚用servlet和jsp做了小的Web项目吗, 假设有人出钱让你再做一个类似的系统,你会怎么办?”

“那我就把现在的代码复制一下, 在上面改改, 不就得了? ”

“如果有十个八个类似这样的项目呢, 难道你都通过复制粘贴来做吗?” Bill 问

“十个八个? 我还是跳楼去吧。 ”

“那你没有想想把其中重复的一些东西抽取出来, 形成可以复用的东西?”

张大胖说: “ 听你这么说,还真的有一点可以复用的东西, 比方说URL和业务代码的映射, 我经常会遇到类似这样的 url : www.xxx.com?action=login , 在后台的servlet 中我就判断, 如果action 的名称是login , 我就把userName, password 这样的参数从表单中提取出来, 执行登录的代码。 我得写很多的if else 才能支持不同的业务逻辑, 很折磨人。 有时候我就想, 要是有一种方法, 能够直接把URL和Java类直接映射起来就好了 , 这样就轻松多了!”

“没错,这是一个很好的想法, 还有吗? ” Bill 笑着问。

“嗯。。。 再比如数据验证啊,比如登录时用户名或者密码出错, 我要在浏览器端显示错误提示信息,这个也很难搞啊, 错误提示的字体、颜色、图标、位置太烦人了。”

“还有吗?”

“对了,访问数据库也是个大问题, 我写了很多的SQL, 很多的JDBC 代码, 仅仅是为了把数据从数据库取出来, 放到Java 对象中去。 你肯定知道,直接用JDBC编程得处理很多细节问题:一定要记住关闭连接了, 处理异常了 。。。等等, 不瞒你说,很多代码都是我复制粘贴的。”

“难道你不能写一个通用的类, 传入SQL,返回结果集吗? ” Bill 问道。

“那我肯定是写了, 但是把结果集变成Java 对象还有一段很长的路呢, 没啥技术含量, 纯粹体力活, 怪不得人家叫我们码农! ” 大胖愤愤的说。

Bill 说: “我刚才翻了翻你的代码, 我发现很多的地方都让人不爽啊, 比如你几乎把所有的业务逻辑都写到Servlet当中去了, 中间还掺杂者页面控制和跳转, 这么乱七八糟像意大利面条一样的代码过了一个月估计你自己都看不明白了。 ”

大胖不好意思的笑了: “不用一个月, 这刚过了一个星期我就犯晕了。”

“所以嘛, 其实你这些问题我们的前辈早就遇到了, 他们也苦苦探索, 不断寻找好的实现方式, 找到以后就把各种经验给固化下来, 称为最佳实践。”

“最佳实践? 能举个例子嘛!”

“比如在Web开发中就有一个很好的实践啊,叫做MVC。 就是针对你上面的业务逻辑和页面控制混在一起提出的解决办法。 这个实践会强烈的建议你把数据模型、页面展示、页面跳转控制分开来写, 防止搅成一团。”

Bill意犹未尽, 继续举例: “再比如你说的第一个问题, 也早就有解决方案了, 可以利用XML或者Java注解来描述URL和Java 类之间的关系,你只需要声明一下, 背后的操作,都交由框架去处理了。 还有你的Java 对象和数据库表的对应关系, 也只需要声明一下,框架就可以帮你把数据取出来,填充到Java对象中去,这就极大的减轻了你的工作量。”

“Bill, 你又提到框架这个词了,可不可以这么说, 框架就像一个模板, 里边已经预置了一些公认的最佳实践,我要是想用的话, 把我项目相关的东西填充进去就可以了,是不是这样? ”

“可以这么理解, 框架像个半成品, 是无法独立运行的,必须由开发人员按照它定义的规则,把项目的代码放置到指定的地方, 由框架整合起来,这才是一个完整的应用程序。”

大胖挠着头说: “那框架其实也没什么啊, 我只要理解了那些最佳实践, 掌握了它的规则,可不就学会了吗?”

“没错, 现在很多Java Web系统都是基于像SpringMVC, Hibernate, MyBatis这样的流行框架构造起来的, 框架不得不学, 但是如果只会使用框架, 只会填充代码, 那只是一个HTML填空人员。”

“那我学完了框架,可以用框架做项目了, 接下来学什么?” 大胖心里有点没底。

“你要是对Java 后端编程感兴趣, 还有很多东西啊, 用框架实现了业务只是很小一块, 还有系统架构设计, 缓存、性能、高可用性、分布式、安全、备份等很多内容啊, 你学的越多,就会发现无知的领域更多, 所谓学无止境啊!”

张大胖目视远方,沉默了。。。。。

张大胖听大神Bill讲解了框架的作用,回去思考了两天,茅塞顿开。

框架只是一个半成品而已, 这个半成品当中固化了很多最佳的实践, 开发人员必须把自己的代码填充到框架当中才能成为一个完整的应用程序。

说起来简单, 到底怎么“填充”呢 ? 码农们写出来的代码怎么才能让框架知道, 并且调用呢?

张大胖本来想找Bill 问个明白, 但转眼一想, 自己要是能思考出结果岂不更加印象深刻? !

他的脑子开始热身,迅速进入高速运转状态, 叮的一声, 一个想法跨入他的脑海: 可以用继承啊!

框架定义一些抽象类(如Java 中的abstract class ) 让具体的应用代码去继承, 抽象类的好处是可以写具体方法, 也可以只声明抽象方法而不实现 – 具体的实现肯定要留给码农们的应用程序了。

在抽象类的具体方法中,可以处理一些框架公用的逻辑, 然后调用那些子类应该实现的抽象方法, 这不就把框架和应用结合起来了吗?

嗯, 这不就是我上周看过的一个著名的设计模式: 模板方法吗? 用在此处挺合适的嘛, 大胖不由的一阵得意, 似乎是自己重新发明了这个设计模式。

模板方法

(注: Action 为抽象类,doBusiness 为抽象方法,其他为具体方法)

张大胖马上向Bill汇报自己的新发明, Bill 鼓励到: “你小子开窍了啊, 这的确是一个办法, 著名的MVC框架struts1 就是这么干的, 还有JUnit的早期版本,更早的EJB1.x, 2.x 都是这样, 都需要自己的业务类/测试类去继承一个框架的抽象类, 实现抽象方法才可以。”

张大胖知道Bill的习惯是先扬后抑, 静静的等待着转折。

“但是,” 转折果然如期而至, “ 这种方法让人感到不爽,业务类比较死板 , 比如你必须得用框架规定的方法名, 没法自己定制。例如JUnit的早期版本, 测试用例的初始化方法必须得叫Setup, 销毁方法必须是TearDown, 你想换成init/destroy 是肯定不行的, 因为框架根本不知道。 ”

张大胖说: “这没什么啊, 我觉得还是比较好的编程实践呢, 大家都保持名称一致,可读性很好啊”

“其实你往深处想想就会明白, 这种方式其实让你的业务类和框架绑定了! 这是最要命的。 你的例子中抽象类是Action , 如果这个Action 很‘重’ ,依赖HttpServletRequest/HttpServletResponse, 必须得有一个Web容器(Tomcat)才能创建起来, 那你的LoginAction 可就悲催了, 想要做个单元测试必须得把Tomcat跑起来才行。 ”

张大胖说:“听你这么一解释, 我明白了,这种继承的方式问题很大啊。 是不是可以这么说, 框架和业务类最好是独立变化, 中间用一座桥来连接起来。”

Bill 赞许道 : “对, 你想想这个桥用什么‘材料’做比较好?”

张大胖挠挠头,一脸懵逼。

“回到原始的问题, 我们不就是试图让框架把我们的业务类创建起来,然后调用特定的方法吗? 完全不用在代码中写死, 可以采用别的声明式的办法啊” Bill 循循善诱。

“难道在代码中写注释? ” 张大胖继续一脸懵逼。

“注释都是纯文本, 不是结构化的信息啊, 难道你让框架读取文本,然后做个语义分析? 根本不可能, 更何况注释在编译过的class中间已经不复存在了,无处可寻, 框架怎么读? 再想想” Bill急得就差自己公布答案了。

“啊, 我知道了,你刚才说的结构化信息提醒了我, 可以用XML啊, XML来描述结构化东西很擅长! ”

张大胖说着还写了个例子出来: “通过用XML来描述, 框架就可以找到相关的类和方法,就可以调用了”

Markdown

“是的, 你举了一个小例子, 实际上由于XML的扩展性, 能描述极为复杂的语义,很多框架都会制定规则, 让码农们去‘声明’自己的业务类及其方法。 “

“这种声明的方式真是不错,业务类不用继承框架的抽象类了,我刚想到一个问题, 我们的Java类和XML配置不在一起, 当我们想知道一个类的方法,字段是怎么被框架使用的时候,还得回过头来查看XML, 这实在不爽。 ” 张大胖问道。

“这是个好问题, 那就把这种‘声明’信息挪到Java 类中去吧!” Bill 说。

“你刚才说了不能用注释, 怎么在Java 文件中写‘声明’ 啊?”

“没有注释, 可以有注解啊! ”

“你是说那个@author, @version, @return, @see这样用来生成Java文档的注解吗? 还有什么@Override,@Deprecated, 我从来都不用。”

Bill 笑了: “那只是Java内置的一些注解, 现在Java可以自定义注解了, 我们完全可以利用这种注解来声明框架想用的信息, 我给你举个例子:”

Markdown

张大胖问道: “@Controller, @ReqeustMapping, @RequestParam 都是框架自定义的注解?“

“是的, 你可以直接在Java 代码中使用, 在运行时框架能读取这些注解, 就知道你想干什么事情了。”

“ 嗯,所有的信息都在Java 中了, 比XML看起来更简洁一些, 果然是十分酸爽。” 张大胖十分感慨 ,“不过,这样一来声明式的信息又四处分散,维护又不方便了。 ”

Bill说: “哪有十全十美的东西? 在编程中根据情况选择吧!