欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

设计模式的七大原则(1) --单一职责原则

程序员文章站 2022-03-20 20:25:51
前言 最近工作中备受打击,之前设计的很多程序都被老大否决,需要重构,让我好好看看设计模式。之前对这一块内容的确不怎么重视,感觉枯燥无聊又派不上用场。后来沉下心来研究了一番... 我靠,原来如此,之前写代码的时候怎么这么傻逼,很多问题其实在一开始设计的时候就能避免。之前写的都是些什么鬼。 我们踩过的坑 ......

前言

最近工作中备受打击,之前设计的很多程序都被老大否决,需要重构,让我好好看看设计模式。之前对这一块内容的确不怎么重视,感觉枯燥无聊又派不上用场。后来沉下心来研究了一番...

我靠,原来如此,之前写代码的时候怎么这么傻逼,很多问题其实在一开始设计的时候就能避免。之前写的都是些什么鬼。

我们踩过的坑,历代前辈们也踩过。可想而知,通他们多年的踩坑填坑经验后,所总结出来的23种设计模式是多么的宝贵,就是我们的“one piece” 啊。如果掌握了这个内容,对今后无论是工作中还是面试都非常重要。因此下定决心,一定要熟练掌握这块内容。记录学习过程,供自己复习也供大家一起学习。

为什么要学习设计模式的目的

在前言中我们已经大致说明,我们总结一下,一个良好的程序应该满足一下六点要求:

1. 可复用性:尽量能重用方法,比如说提取某种工具类。
2. 可读性:编程具备规范性,阅读起来不困难。
3. 可扩展性:当你写好的程序需要添加一个新功能的时候,不能说:不行!非要添加的话我要重构代码。
4. 稳定性:尽可能少的bug。
5. 高内聚:每个模块尽可能独立完成自己的功能,不依赖于模块外部的代码。
6. 低耦合:并且模块之间联系越复杂耦合度越低,就不会牵一发而动全身。否则模块a的bug甚至会导致模块b无法运行

这是多代前辈们总结出来的编程经验,如果我们的程序没有以上特点,就会出现很多bug。我们要站在巨人的肩膀上。尽量多学习多总结,避免犯“古人”们常犯的错误。

设计模式的作用就出来了,设计模式的目的就是为了让我们的程序具备以上六点特性。

设计模式常用的七大原则

在学习设计模式之前,为了不让设计模式显得很模式,我们还必须了解一个东西,那就是程序设计七大原则(很多地方说的是六大原则,但还有一个合成复用原则也值得提出来)。

这些原则是指导模式的规则,我会给一些原则附上一个例子,来说明这个原则所要表达的意思,注意,原则是死的,人是活的,所以并不是要你完完全全遵守这些规则,否则为何数据库会有逆范式,只是在可能的情况下,请尽量遵守。

七大原则分别是:

1. 单一职责原则(single responsibility principle)
2. 接口隔离原则(interface segregation principle)
3. 依赖倒置原则(dependence inversion principle)
4. 里氏替换原则(liskov substitution principle)
5. 开闭原则(open close principle)
6. 迪米特法则(law of demeter)
7. 合成复用原则(composite/aggregate reuse principle carp)

单一职责原则

看名字就能知道,我们设计的类要尽可能的只负责一项职责。比说说a类只负责a功能,b类只负责b功能,不要a类既负责a功能又负责b功能。

为什么要这样设计?

当a功能需要更新,那么就得去修改a类。如果此时a还负责b功能,就很有可能修出bug后导致b功能的正常使用。或者说,想实现b功能却调用的a功能的接口,这样会导致程序运行混乱。总结以下几点:

1. 降低类的复杂度,一个类只负责一项职责。
2. 提高类的可读性,可维护性。
3. 降低变更引起的风险。
4. 通常情况下,我们应当遵守单一职责原则,只要逻辑足够简单,才可以在代码级别违反单一职责原则:也就是说类中的方法数量足够少,可以在方法级别保持单一职责原则。下述代码将会说明。

例如以下代码:

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应该尽量的少用,要不耦合会非常严重,去看看优秀源码也是如此。可以思考思考使用单一职责原则,用类来划分多分支。

总结

今天就到这里,一个一个慢慢吃透,一天进步一点。下一篇我们来看接口隔离原则。