前言
最近工作中备受打击, 之前设计的很多程序都被老大否决, 需要重构, 让我好好看看设计模式. 之前对这一块内容的确不怎么重视, 感觉枯燥无聊又派不上用场. 后来沉下心来研究了一番...
我靠, 原来如此, 之前写代码的时候怎么这么傻逼, 很多问题其实在一开始设计的时候就能避免. 之前写的都是些什么鬼.
我们踩过的坑, 历代前辈们也踩过. 可想而知, 通他们多年的踩坑填坑经验后, 所总结出来的 23 种设计模式是多么的宝贵, 就是我们的 "ONE PIECE" 啊. 如果掌握了这个内容, 对今后无论是工作中还是面试都非常重要. 因此下定决心, 一定要熟练掌握这块内容. 记录学习过程, 供自己复习也供大家一起学习.
为什么要学习设计模式的目的
在前言中我们已经大致说明, 我们总结一下, 一个良好的程序应该满足一下六点要求:
可复用性: 尽量能重用方法, 比如说提取某种工具类.
可读性: 编程具备规范性, 阅读起来不困难.
可扩展性: 当你写好的程序需要添加一个新功能的时候, 不能说: 不行! 非要添加的话我要重构代码.
稳定性: 尽可能少的 bug.
高内聚: 每个模块尽可能独立完成自己的功能, 不依赖于模块外部的代码.
低耦合: 并且模块之间联系越复杂耦合度越低, 就不会牵一发而动全身. 否则模块 A 的 bug 甚至会导致模块 B 无法运行
这是多代前辈们总结出来的编程经验, 如果我们的程序没有以上特点, 就会出现很多 BUG. 我们要站在巨人的肩膀上. 尽量多学习多总结, 避免犯 "古人" 们常犯的错误.
设计模式的作用就出来了, 设计模式的目的就是为了让我们的程序具备以上六点特性.
设计模式常用的七大原则
在学习设计模式之前, 为了不让设计模式显得很模式, 我们还必须了解一个东西, 那就是程序设计七大原则 (很多地方说的是六大原则, 但还有一个合成复用原则也值得提出来).
这些原则是指导模式的规则, 我会给一些原则附上一个例子, 来说明这个原则所要表达的意思, 注意, 原则是死的, 人是活的, 所以并不是要你完完全全遵守这些规则, 否则为何数据库会有逆范式, 只是在可能的情况下, 请尽量遵守.
七大原则分别是:
单一职责原则 (Single Responsibility Principle)
接口隔离原则 (Interface Segregation Principle)
依赖倒置原则 (Dependence Inversion Principle)
里氏替换原则 (Liskov Substitution Principle)
开闭原则 (Open Close Principle)
迪米特法则 (Law Of Demeter)
合成复用原则 (Composite/Aggregate Reuse Principle CARP)
单一职责原则
看名字就能知道, 我们设计的类要尽可能的只负责一项职责. 比说说 A 类只负责 A 功能, B 类只负责 B 功能, 不要 A 类既负责 A 功能又负责 B 功能.
为什么要这样设计?
当 A 功能需要更新, 那么就得去修改 A 类. 如果此时 A 还负责 B 功能, 就很有可能修出 BUG 后导致 B 功能的正常使用. 或者说, 想实现 B 功能却调用的 A 功能的接口, 这样会导致程序运行混乱. 总结以下几点:
降低类的复杂度, 一个类只负责一项职责.
提高类的可读性, 可维护性.
降低变更引起的风险.
通常情况下, 我们应当遵守单一职责原则, 只要逻辑足够简单, 才可以在代码级别违反单一职责原则: 也就是说类中的方法数量足够少, 可以在方法级别保持单一职责原则. 下述代码将会说明.
例如以下代码:
- public class SingleResponsibility1 {
- public static void main(String args[]) throws IOException {
- Computer computer = new Computer();
- computer.add();
- }
- }
- // 读取配置文件和计算
- class Computer{
- public int add() throws NumberFormatException, IOException {
- File file = new File("D:/data.txt");
- BufferedReader br = new BufferedReader(new FileReader(file));
- int a = Integer.valueOf(br.readLine());
- int b = Integer.valueOf(br.readLine());
- return a+b;
- }
- }
在这个 Computer 类中有一个 add 方法, 负责读取配置文件数字, 然后再进行相加.
这个类很明显违反了单一职责原则, 一个类既负责了读取文件, 又负责算数. 大家考虑一下这样设计有没有什么问题?
问题诸多, 提高代码可维护性, 报错不好定位, 功能耦合...
来看看更新后的代码是什么样子的:
- public class SingleResponsibility2 {
- public static void main(String args[]) throws IOException {
- readFile readFile = new readFile();
- readFile.read("D:/data.txt");
- Computer2 computer = new Computer2();
- computer.add(readFile.getA(),readFile.getB());
- }
- }
- // 计算
- class Computer2 {
- public int add(int a, int b){
- return a + b;
- }
- }
- // 读取配置文件
- class readFile {
- private int a;
- private int b;
- public void read(String path) throws IOException {
- File file = new File(path);
- BufferedReader br = new BufferedReader(new FileReader(file));
- a = Integer.valueOf(br.readLine());
- b = Integer.valueOf(br.readLine());
- }
- public int getA() {
- return a;
- }
- public int getB() {
- return b;
- }
- }
通过这样修改代码, 我们实现了单一职责原则.
这样就万无一失了吗?
当然有时候也不见得, 因为如果我们的代码足够简单, 这样设计会提供编写代码的成本. 并且同时还要修改客户端代码.
我们再来看看下面的代码:
- public class SingleResponsibility3 {
- public static void main(String args[]) throws IOException {
- Computer3 computer = new Computer3();
- computer.read("D:/data.txt");
- computer.add(computer.getA(),computer.getB());
- }
- }
- // 负责读取配置文件, 并且负责计算
- class Computer3 {
- private int a;
- private int b;
- public void read(String path) throws IOException {
- BufferedReader br = new BufferedReader(new FileReader(path));
- a = Integer.valueOf(br.readLine());
- b = Integer.valueOf(br.readLine());
- }
- public int getA() {
- return a;
- }
- public int getB() {
- return b;
- }
- public int add(int a, int b){
- return a + b;
- }
- }
当然这个只是示例代码, 在真正的开发环境也不可能这样用. 我举这个例子只是想说明如果一个类的方法很少功能逻辑比较简单. 如我们写的 Computer 类, 只负责读取两个数, 然后相加.
这样简单的类其实就可以在代码级别违反单一职责原则: 也就是说类中的方法数量足够少, 可以在方法级别保持单一职责原则.
还是那句话: 人是活的, 原则是死的.
一个优秀的代码 if else 应该尽量的少用, 要不耦合会非常严重, 去看看优秀源码也是如此. 可以思考思考使用单一职责原则, 用类来划分多分支.
总结
今天就到这里, 一个一个慢慢吃透, 一天进步一点. 下一篇我们来看接口隔离原则.
来源: https://www.cnblogs.com/zhxiansheng/p/11212355.html