java设计模式之7大面向对象设计原则

面向对象设计原则

我们在进行软件开发时,不仅仅需要将最基本的业务给完成,还要考虑整个项目的可维护性和可复用性,我们开发的项目不单单需要我们自己来维护,同时也需要其他的开发者一起来进行共同维护,因此我们在编写代码时,应该尽可能的规范。

7大面向对象设计原则

单一职责原则(Single Responsibility Principe,SRP)

  • 是最简单的面向对象设计原则,它用于控制类的大小

  • 定义:一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中

class Coder{
    public void coding(){
        System.out.println("程序员会编程")
    }
}
​
class Worker{
    public void work(){
        System.out.println("工人会打螺丝");
    }
}
​
class Rider{
    public void ride(){
        System.out.println("骑手会送外卖");
    }
}

开闭原则(Open Close Principle,OCP)

  • 定义:软件实体应当对扩展开发,对修改关闭

  • 将一个行为抽象成一个统一的接口或是抽象类,具体代码由不同的对象去实现

public abstract class Coder{
    
    public abstract void coding();
    
    class JavaCoder extends Coder{
        @Override
        public void coding(){
            SYstem.out.println("Java太卷了,快去学Go吧!");
        }
    }
    
    class PHPCoder extends Coder{
        @Override
        public void coding(){
            SYstem.out.println("PHP是世界上最好的语言!");
        }
    }
    
    class CCoder extends Coder{
        @Override
        public void coding(){
            SYstem.out.println("笑死,Java再牛逼底层不还得是我?");
        }
    }
    
}

里氏替换原则(Liskov Substitution Principle,LSP)

  • 是对子类型的特别定义,它由芭芭拉.利斯科夫(Barbara Liskov)在1987年在一次会议上名为“数据的抽象与层次”的演说中首先提出

  • 定义:所有引用基类的地方必须能透明地使用其子类的对象

  • 简单地说就是,子类可以扩展父类的方法,但不能改变父类原有的功能

    • 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。

    • 子类可以增加自己特有的方法。

    • 当子类的方法重载父类的方法时,方法的前置条件(即方法的输入/入参)要比父类方法的输入参数更宽松

    • 当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类更严格或与父类一样

public abstract class Coder{
    
    public void coding(){
        System.out.println("我会打代码");
    }
    
    class JavaCoder extends Coder{
        public void game(){
            System.out.println("子类除了会打代码之外,还会打游戏!");
        }
    }
}

可以看到JavaCoder虽然继承自Coder,但是并没有对父类方法进行重写,并且还在父类的基础上进行额外扩展,符合里氏替换原则。

  • 最佳优化

public abstract class People{
    
    public abstract void coding();  //这个行为还是定义出来,但是不实现
    
    class Coder extends People{
        @Override
        public void coding(){
            System.out.println("我会打代码");
        }
    }
    
    class JavaCoder extends People{
        public void game(){
            System.out.println("子类除了会打代码之外,还会打游戏!");
        }
        
        public void coding(){
             System.out.println("摆烂了,啊对对对");
        }
    }
}
  • 里氏替换也是实现开闭原则的重要方式之一。

依赖倒转原则(Dependence Inversion Principle,DIP)

  • 最明显的是Spring框架

  • 定义:高层模块不应该依赖于低层模块,它们都应该依赖抽象,抽象不应该依赖于细节,细节应该依赖于抽象。

public class Main{
    
    public static void main(String[] args){
        UserController controller = new UserCOntroller();
    }
    
    interface UserMapper{
        //接口中只能做CRUD方法
    }
    
    static class UserMapperImpl implements UserMapper{
        //实现类完成CRUD具体实现
    }
    
    interface UserService{
        //业务代码定义....
    }
    
    static class UserServiceImpl implements UserService{
        @Resource   //现在由Spring来为我们选择一个指定的实现类,然后注入,而不是由我们在类中硬编码进行指定
        UserMapper mapper;
        
        //业务代码具体实现
    } 
    
    static class UserController{
        @Resource
        UserService service;    //直接使用接口,就算改实现,也不需要再修改代码
        
        //业务代码
    }
}

可以看到,通过使用接口,我们就可以将原有的强关联给弱化,我们只需要知道接口中定义了什么方法然后去使用即可,而具体的操作有接口的实现类来完成,并由Spring来为我们注入,而不是我们通过硬编码的方式去指定

接口隔离原则(Interface Segregation Principle,ISP)

  • 实际上是读接口的细化

  • 定义:客户不应该依赖那些它不需要的接口

interface SmartDevice{  //智能设备才有getCpu和getMemory
    String getCpu();
    String getType();
    String getMemory();
}
​
interface NormalDevice{ //智能设备只有getType
    String getType();
}
​
//电脑就是一种电子设备,那么就继承此接口
class Computer implements SmartDevice{
    
    @Override
    public String getCpu(){
        return "i9-12900K";
    }
    
    @Override
    public String getType(){
        return "电脑";
    }
    
    
    @Override
    public String getMemory(){
        return "32G DDR5";
    }
}
​
//风扇也是一种电子设备
class Fan implements NormalDevice{
    @Override
    public String getType(){
        return "风扇";
    }
}

合成复用原则(Composite Reuse Principle,CRP)

  • 核心就是委派

  • 定义:优先使用对象组合,而不是通过继承来达到复用的目的

class A{
    public void connectDatabase(){
        System.out.println("我是连接数据库操作!");
    }
}
​
class B{    //不进行继承,而是在用的时候给一个A,当然也可以抽象成一个接口,更加灵活
    public void test(A a){
        System.out.println("我是B的方法,我也需要连接数据库!");
        a.connectDatabase();    //在通过传入的对象A去执行
    }
    
}

或是

class A{
    public void connectDatabase(){
        System.out.println("我是连接数据库操作!");
    }
}
​
class B{
    A a;
    public B(A a){  //在构造时就指定好
        this.a = a;
    }
    
    public void test(){
        System.out.println("我是B的方法,我也需要连接数据库!");
        a.connectDatabase();    //也是通过对象A去执行
    }
}

通过对象之间的组合,大大降低了类之间的耦合度

迪米特法则(Law of Demeter)

  • 又称最少知识原则,是对程序内部数据交互的限制

  • 定义:每一个软件单位对其他单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位

public class Main{
    public static void main(String[] args) throws IOException{
        Socket socket = new Socket("localhost",8080);
        Test test = new Test();
        test.test(socket.getLocalAddress().getHostAddress());	//在外面解析
    }
    
    static class Test{
        public void test(String str){	//一个字符串就能搞定,就没必要丢整个对象进来
            System.out.println("IP地址:" + str);
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鱼粮爱编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值