6

设计模式——面向对象设计原则 - 不吃紫菜

 2 years ago
source link: https://www.cnblogs.com/buchizicai/p/16580687.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

面向对象设计原则

都是为了高内聚低耦合原则。编程时基本都要遵守

单一职责原则

分类原则:一种人只干一种事。

举例:(比较简单就不代码了)

人可以干的事情有很多:敲代码、唱歌、跳舞、打篮球....以人设置成一个类,里面的方法就太多太杂了。所以可以有多个类:程序员(敲代码)、音乐人(唱歌)、爱豆(跳舞)、NBA球员(打篮球)。这样类就具体化了,可以干的事情也就具体了,一旦需要用哪个方法就知道从哪个类里调用了。

开:提供方提供 抽象类/接口/方法 等,实现类可以决定行为。闭:调用方调用时,尽量不需要修改代码。

定义:一个软件实体,比如类、模块和函数应该对扩展开放,对修改关闭。其中,对扩展开放是针对提供方来说的,对修改关闭是针对调用方来说的。

//接口
public interface AccountService {
    //实现注册账户
    void createAccount(String username,String password,String email);

}

//实现类
public class AccountServiceImpl implements AccountService {
        public void createAccount(String username,String password,String email) {
            ....
        }
}

里氏替换原则

对子类的特别定义:父类方法非抽象方法,子类不可以重载(覆盖)。但如果父类有抽象方法则子类必须实现父类的抽象方法,子类也可以编写自己的方法

里氏替换原则(Liskov Substitution Principle)是对子类型的特别定义。所有引用基类的地方必须能透明地使用其子类的对象。

白话:子类可以扩展父类的功能,但不能改变父类原有的功能。有以下四原则:(重点在一二)

  1. 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
  2. 子类可以增加自己特有的方法。
  3. 当子类的方法重载父类的方法时,方法的前置条件(即方法的输入/入参)要比父类方法的输入参数更宽松。
  4. 当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类更严格或与父类一样。

如:子类继承了父类,但没有修改父类的非抽象方法

public abstract class Coder {
     public abstract void eat();   //这个行为还是定义出来,但是不实现

    public void coding() {
        System.out.println("我会打代码");
    }


    class JavaCoder extends Coder{
        public void game(){		//子类自己的额外的方法
            System.out.println("艾欧尼亚最强王者已上号");
        }
        
        public void eat(){	//子类实现父类的抽象方法(必须)
            System.out.println("干啥啥不行,干饭第一名!")
        }
    }
}

依赖倒转原则

使用Spring注解 注入接口,这样需求更改后实现类可以自由编写,不会影响到controller层(将每一层都分隔开来降低耦合性)

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

传统:没有接口而是类与类之间的对象创建。一旦需求变化,类就需要重写,这样其他类也需要修改

public class Main {

    public static void main(String[] args) {
        UserController controller = new UserController();
    }

    static class UserMapper {
        //CRUD...
    }

    static class UserServiceNew {   //由于UserServiceNew发生变化,会直接影响到其他高层模块
        UserMapper mapper = new UserMapper();
        //业务代码....
    }

    static class UserController {   //焯,干嘛改底层啊,我这又得重写了
        UserService service = new UserService();   //哦豁,原来的不能用了
        UserServiceNew serviceNew = new UserServiceNew();   //只能修改成新的了
        //业务代码....
    }
}

Spring框架:使用注解注入接口bean,这样实现类可随便改,只要最后的实现类实现了该接口即可

//controller
public class LoginApiController {
    @Autowired	//Spring注解注入接口bean
    private VerifyService verifyService;

    @GetMapping("/verify-code")
    public RestBean<Void> verifyCode(@RequestParam("email") String email) {
        try {
            verifyService.sendVerifyCode(email);
            return new RestBean<>(200, "邮箱发送成功!");
        } catch (Exception e) {
            return new RestBean<>(500, "邮箱发送失败!");
        }
    }
}
    
    

接口隔离原则

对接口进行细分,避免接口中定义的方法,在实现类中用不上。

举例:定义一个接口,有方法:设备芯片、设备名称、设备内存。这样的接口只有电脑、手机等实现类才可以实现,而对于风扇、台灯等普通设备实现类而言确只有设备名称才是有效的方法。于是就需要把接口进行细化成两个接口。

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)的核心就是委派。

情况:如果A类里写了想要的方法,为了不在B类不重复编写代码,可以在B类中设置一个方法:将A类的对象作为参数并在设置的方法里通过对象获取到A类中想要的方法。【此时不建议使用继承,因为容易引起安全隐患,如: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)又称最少知识原则,是对程序内部数据交互的限制。

简单来说就是,一个类/模块对其他的类/模块有越少的交互越好。当一个类发生改动,那么,与其相关的类(比如用到此类啥方法的类)需要尽可能少的受影响(比如修改了方法名、字段名等,可能其他用到这些方法或是字段的类也需要跟着修改)这样我们在维护项目的时候会更加轻松一些。

白话:在设计方法参数的时候,保证不多给方法多余的参数。例如:方法只需要一个用户的ip地址就可以执行,方法参数就不要写成需要输入用户对象,然后在方法里面通过对象再去调用其ip出来;而是在调用方法前就把用户对象的ip取出来,然后作为参数来调用方法。

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);
        }
    }
}
public class Main {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("localhost", 8080);   //假设我们当前的程序需要进行网络通信
        Test test = new Test();
        test.test(socket);   //现在需要执行test方法来做一些事情
    }

    static class Test {
        /**
         * 比如test方法需要得到我们当前Socket连接的本地地址
         */
        public void test(Socket socket){
            System.out.println("IP地址:"+socket.getLocalAddress());
        }
    }
}

Recommend

  • 41
    • yi-love.github.io 6 years ago
    • Cache

    面向对象设计原则之迪米特原则

    免责声明:本文内容大都来源于网络 迪米特原则定义 狭义的迪米特原则定义:也叫最少知识原则(LKP,Least Knowledge Principle)。如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中的一...

  • 49

    昨天我看了单一职责原则和开闭原则,今天我们再来看里式替换原则和依赖倒置原则,千万别小看这些设计原则,他在设计模式中会有很多体现,所以理解好设计原则之后,那么设计模式,也会让你更加的好理解一点。 前言 在...

  • 60
    • www.tuicool.com 5 years ago
    • Cache

    面向对象的设计原则最终篇

    关于面向对象的设计原则我之前已经解释过四种了,分别是单一职责原则,开放关闭原则,里式替换原则,依赖倒置原则而接下来我们要解释的就是最后的三种原则了,分别是接口隔离原则, 迪米特法则, 组合复用原则 前言 ...

  • 42

    在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用这些对象的目的。 如果两个类是“Has-a”关系应使用合成、聚合,如果是“Is-a”关系可使用继承。”Is-A”是严格的分类学意义上定义...

  • 28

    里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能...

  • 11

    面向对象设计原则 开放封闭原则:   一个软件实体如类、模块和函数应该对拓展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。 里氏替换原则:   所有引用的父类的地方必须能透明的使用其子类的对象

  • 4
    • www.cnblogs.com 2 years ago
    • Cache

    JPA作持久层操作 - 不吃紫菜

    JPA(Hibernate是jpa的实现) jpa是对实体类操作,从而通过封装好的接口直接设置数据库的表结构。虽然jpa可以直接通过编写java代码来操作数据库表结构,避免了sql的编写,但别忘了需要先建立jpa需要操作的数据库...

  • 1

    结构性设计模式 针对类与对象的组织结构。(白话:类与对象之间的交互的多种模式 类/对象适配器模式 当需要传入一个A类型参数,但只有B类型类时,就需...

  • 7

    行为型设计模式 针对对象之间的交互 解释器模式 java中用的很。JVM编译的时候就是对我们写的代码进行了解释操作;数据库SQL语句亦是如此 ...

  • 9

    Ribbon负载均衡 SpringCloud已经删除了ribbon组件,所以需要手动导入依赖。(要学是因为很多项目业务已经使用了ribbon) 服务拉取的时候添加了@LoadBalanced注解,实现负载均衡

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK