【Android】六大设计原则

六大设计原则

为了提高代码的可维护性,可扩展性,减少开发人员开发和维护的成本,减少系统出错;我们需要做到高内聚,低耦合;那么这里有六大设计原则,快来学习一下把;

单一职责原则(SRP)

介绍:

一个类应该只有一个引起它变化的原因。每一个类应该只负责一个职责。

违反常见问题:

  1. 当一个类承担过多职责时,耦合度比较高,当一个实则需要修改时,可能会导致其他职责被迫修改;
  2. 由于职责较多代码量较大,开发人员维护困难;
  3. 难以进行单个功能的测试;

例子:

java 复制代码
public class SRP {
    private int elpee;
    private int money;

    public SRP(int elpee, int money) {
        this.elpee = elpee;
        this.money = money;
    }

    public int getMoney() {
        return money;
    }
    public int getreport() {
        return 12;
    }
}

修改后:

java 复制代码
public class SRP {
    private int elpee;
    private int money;

    public SRP(int elpee, int money) {
        this.elpee = elpee;
        this.money = money;
    }

    public int getMoney() {
        return money;
    }
}
class getmoney{
    public int getMoney(SRP S) {
        return S.getMoney();
    }
}
class getreport{
    public int getrepoet(SRP S) {
        return 23;
    }
}

修改前后的区别在于为不同的功能创建了不同的类,这样的话如果要修改类,不需要需要SRP这个类,只需要修改对应的功能类就好,还方便测试等;

可能违反SRP的情况:

  1. 当一个类承担了很多职责,比如ui,数据库,业务逻辑处理;
  2. 当一个类被修改多次;
  3. 方法很多的时;

扩展点:

我们可以引入多层次的划分,例如:

  • 业务逻辑层:具体的业务和数据处理;
  • 数据访问层:与数据库文件等数据存储相关操作;
  • 服务层:封装业务逻辑层,数据访问层的交互;

根据不同层次的划分,使用单一职责原则更加得心应手;

开放-关闭原则(OCP)

介绍:

软件实体(如类、模块、函数等)应该对扩展开放,对修改关闭。当有需求变化时,软件系统应该拓展新功能,而不是修改现有的代码;

优点:

  1. 有利于代码的稳定性和可维护性。当有新功能时,我们不修改现有的类或者方法,而是通过继承或者接口去添加新的模块来实现功能;
  2. 减少代码量的重复。只需要扩展特定的模块,不需要在系统其他地方去增加代码量,减少代码量;
  3. 减少修改风险。减少因为修改代码而破坏已有功能;

如何实现:

开放-关闭原则通常依赖于多态性继承接口编程,而非依赖具体实现;在不修改原有代码的基础上进行扩展;

这里选择了策略模式来实现OCP原则:

策略模式:定义一系列算法(策略),并将每种算法封装到独立的类中,使它们可以互相替换;客户端(使用者)可以在运行时选择不同的策略,而不用修改原有代码。

java 复制代码
class OrderService {
    public double calculateDiscount(String type, double price) {
        if ("normal".equals(type)) {
            return price;
        } else if ("vip".equals(type)) {
            return price * 0.9;
        } else if ("svip".equals(type)) {
            return price * 0.8;
        }
        return price;
    }
}

现在需要新增功能,那么就是需要新增else if语句,如果在软件系统其他地方用到,那么就会新增代码量;那么使用ocp原则这么写:

java 复制代码
public interface dis {
    public double discount(double count);
}

public class vip implements  dis{
        @Override
        public double discount(double count) {
            return 0.9*count;
        }
    }
 class vvip implements  dis{
        @Override
        public double discount(double count) {
            return 0.8*count;
        }
    }
class discount{
    public double getdiscout(dis dis,double money){
        return dis.discount(money);
    }
}

定义一个接口,功能通过实现这个接口的方法来完成,通过一个类,参数是接口,通过多态来调用不同类中的方法来实现功能;

里氏替换原则(LSP)

介绍:

  1. 定义:任何基类可以出现的地方,子类一定可以出现。
  2. 和开闭原则的关联:里氏替换原则其实是对开闭原则的补充,开闭原则的重要一步就是抽象化,基类和子类的继承就是抽象化的一种表现,那么LSP就是对实现抽象化的规范;
  3. 为什么要这么要求:这么要求的情况下,子类才是对基类做到了扩展,有利于代码的维护和减少了错误;

这就要求我们尽量不要重写和重载基类的方法,否则有可能造成基类的方法原有功能的故障;(有时候我们会使用final来强制遵循);不仅如此,假如改变了基类,那么所有的子类有可能会发生故障;

如何实现:

java 复制代码
public class LSP {
    public void say(){
        System.out.println("所有人都好可爱");
    }
}
class  lsp extends LSP{
    @Override
    public void say(){
        System.out.println("刘浩存真可爱");
    }
}

这里将say方法进行了重写,那么我们将无法使用基类的功能,所有人都好可爱;

解决办法有三种:

java 复制代码
   class  lsp extends LSP{
       @Override
       public void say(){
           super.say();
           System.out.println("刘浩存真可爱");
       }
   }

保留父类的方法和功能,子类进行扩展;

  1. 重新写构造一个方法功能,不重写,写一个Liusay()方法;

  2. 抽象出一个新类,使得父类和子类都去继承这个类;把原来的继承关系去掉,采用依赖,组合等关系代替;

理解里氏替换原则:

核心:不改变父类的功能,而是对父类的功能进行扩展;

  1. 不改变父类的功能:可以实现抽象方法,但不能覆盖父类的非抽象方法;
  2. 可以增加新的方法功能;
  3. 当子类重载父类的方法时,后置条件(参数)要比父类更宽松,使得能使用父类这个功能的条件也能使用子类的方法;
  4. 当子类实现父类的抽象方法时,前置条件(返回值)要比父类更严格;可以代替而且还更加精确了;

依赖倒置原则(DIP)

介绍

  1. 定义:高层模块不应该依赖底层模块,而是依赖于抽象;抽象不应该依赖于细节,细节依赖于抽象;

优点

  1. 降低了耦合度;
  2. 增加了可维护性和可拓展性;

实例:

java 复制代码
public class DIP {
    public void dog(){
        System.out.println("我是一只可爱小狗");
    }
}
class dip {
    public void animal(DIP D){
        D.dog();
    }
}

这里dip类依赖于低层模块DIP,违反了依赖倒置原则;

java 复制代码
interface jiekou{
    void animal();
}
public class DIP implements jiekou{
    @Override
    public void animal() {
        System.out.println("我是一只可爱小狗");
    }
}
class cat implements jiekou{

    @Override
    public void animal() {
        System.out.println("我是一只可爱小(>^ω^<)喵");
    }
}
class dip {
    public void say(jiekou a){
        a.animal();
    }
}

这里即使新增加低层,也蛮符合单一职责原则的;

这里有一个接口,低层实现这个接口,那么高层则可以依赖接口而不是依赖细节;这里细节指的是具体的实现;

迪米特法则(lOD)

介绍

  1. 也称最少知识原则,一个对象尽可能少的了解其他对象的细节;一个对象不应该过多的依赖其他对象的内部结构和实现细节。对象之间应该尽可能通过有限的,直接的接口进行,不是一长串的调用链;
  2. 只与朋友通信,不与陌生人通信;

这里的朋友是指:

  1. 自身:自己的方法和属性;
  2. 成员对象:;
  3. 方法参数;
  4. 创建的对象;
  5. 全局变量或实例对象;

实例:

java 复制代码
public class LOD {
    public lod getlhc(){
        return  new lod();
    }
}
class lod{
    public  void getljx(){
        
    }
}
class lods{
    public  void get(LOD lod){
          lod.getlhc().getljx();
    }
}

这里lods类直接依赖于lod,不应该暴露lod类,违反了迪米特法则;

java 复制代码
public class LOD {
    private lod lod;
    public void getlhc(){
       lod.getljx();
    }
}
class lod{
    public  void getljx(){

    }
}
class lods{
    public  void get(LOD lod){
          lod.getlhc();
    }
}

这里使用了方法对lod类的对象进行了封装,直接调用,而不是新new了一个对象,把对象暴露了出来违法法则;

接口隔离原则(ISP):

介绍:

一个类对另一个类的依赖应该建立在最小的接口上;

接口尽量小而精;不要建立庞大的接口,接口中的方法最好少而精;

尽量为一个类定制一个接口,而不是用一个庞大接口使依赖它的所有类通用;

例子:

比如ISP类代表汽车,需要实现三个方法 void chesu();void qiyou(); void gonglv();

但是isp类代表风扇,需要实现两个方法 shansu()void gonglv();

java 复制代码
interface dianqi{
    void chesu();
    void qiyou();
    void gonglv();
}
public class ISP implements dianqi{

    @Override
    public void chesu() {
        
    }

    @Override
    public void qiyou() {

    }

    @Override
    public void gonglv() {

    }
}
class isp implements dianqi{

    public void shansu() {

    }
    @Override
    public void chesu() {
      //不需要
    }

    @Override
    public void qiyou() {
        //不需要
    }

    @Override
    public void gonglv() {
  
    }
}

这样的接口就很臃肿;而且实现了不需要的两个方法;

java 复制代码
interface dianqi{
    void gonglv();
}
interface ISPI{
    void chesu();
    void qiyou();
}
interface shan{
    void shnsu();
}

这样设计的接口合理且精确;

我们有几个注意事项:

  1. 接口尽量小,但是要有限度;接口的粒度较小,可以增加灵活性;但接口的数量过多,也会使设计复杂化;
  2. 建立最小的依赖关系,给需要依赖的类定制方法;

优点:

降低耦合度,提高可维护性和灵活性;

本次介绍到此结束,谢谢大家!

相关推荐
小霞在敲代码3 小时前
HashMap - 底层原理
java·hashmap
孙同学要努力3 小时前
《Linux篇》进程状态——浅度、深度睡眠状态、僵尸状态、运行状态
linux·运维
Elsa️7464 小时前
个人项目开发(1):使用Spring Secruity实现用户登录
java·后端·spring
麦芽糖02194 小时前
springboot集成ZeroMQ
java·spring boot·后端
jieyu11194 小时前
Linux Rootkit 详解
linux·运维·系统安全
weixin_456904274 小时前
C# 中的回调函数
java·前端·c#
宁檬精4 小时前
运维面试准备——综合篇(一)
linux·运维·服务器
程序员水自流4 小时前
MySQL InnoDB存储引擎关键核心特性详细介绍
java·数据库·mysql
阿巴~阿巴~4 小时前
Ubuntu 20.04 安装 Redis
linux·服务器·数据库·redis·ubuntu