设计模式七大原则

一、Single Responsibility Principle

  • 一个类只负责一项职责,提高代码易读性,可维护性

1. 传统模式

  • 一个类中的方法,具备了不同种类的错误的功能,违反了单一职责
package com.design.pattern.day01;

public class Demo01 {
    public static void main(String[] args) {
        Vehicle plane = new Vehicle("飞机");
        plane.run();

        Vehicle boot = new Vehicle("轮船");
        boot.run();

        Vehicle bike = new Vehicle("自行车");
        bike.run();
    }
}

class Vehicle {

    private String name;

    public Vehicle(String name) {
        this.name = name;
    }

    public void run() {
        System.out.println(name + "在天上飞");
    }
}

2. 基于类

  • 每个类都负责该类中所有功能,如果需要在该类中添加对应的功能,不会影响其他类中,符合单一职责原则
  • 当类中的方法较少的时候,创建多个类会增大虚拟机开销
package com.design.pattern.day01;

public class Demo02 {
    public static void main(String[] args) {
        PlaneVehicle planeVehicle = new PlaneVehicle();
        planeVehicle.run();

        BikeVehicle bikeVehicle = new BikeVehicle();
        bikeVehicle.run();

        BootVehicle bootVehicle = new BootVehicle();
        bootVehicle.run();
    }
}

class PlaneVehicle {
    private String name = "飞机";

    public void run() {
        System.out.println(name + "天上飞");
    }
}

class BootVehicle {
    private String name = "船";

    public void run() {
        System.out.println(name + "水里游");
    }
}

class BikeVehicle {
    private String name = "自行车";

    public void run() {
        System.out.println(name + "路上走");
    }
}

3. 基于方法

  • 当逻辑足够简单或者类中方法较少时,可以不在类上,而是在方法上遵循单一职责原则
package com.design.pattern.day01;

public class Demo01 {
    public static void main(String[] args) {
        Vehicle plane = new Vehicle("飞机");
        plane.fly();

        Vehicle boot = new Vehicle("轮船");
        boot.swim();

        Vehicle bike = new Vehicle("自行车");
        bike.walk();
    }
}

class Vehicle {

    private String name;

    public Vehicle(String name) {
        this.name = name;
    }

    public void fly() {
        System.out.println(name + "在天上飞");
    }

    public void swim() {
        System.out.println(name + "在水里游");
    }

    public void walk() {
        System.out.println(name + "在路上走");
    }
}

二、Interface Segregation Principle

  • 一个类对另外一个类的依赖,应该建立在最小接口的原则上

1. 传统模式

package com.design.pattern.day01;

public class Demo03 {
    public static void main(String[] args) {
        /**
         * 1. SportStarManager和SingerStarManager基于接口Star
         *    分别依赖于SingerStar和SportStar
         *    
         * 2.  但是接口的所有功能混杂在一起,就导致了不恰当的方法调用
         *     SportStarManager能调用到 sing()
         *     SingerStarManager能调用到 playBall()
         */
    }
}

class SportStarManager {
    private Star star;

    public SportStarManager(Star star) {
        this.star = star;
    }

    public void dailyWork() {
        star.eat();
        star.sleep();
        star.drink();
        star.playBall();

        star.sing();
    }
}

class SingerStarManager {
    private Star star;

    public SingerStarManager(Star star) {
        this.star = star;
    }

    public void dailyWork() {
        star.drink();
        star.eat();
        star.sleep();
        star.sing();

        star.playBall();
    }
}

class SingerStar implements Star {

    @Override
    public void eat() {
        System.out.println("刘德华吃饭");
    }

    @Override
    public void sleep() {
        System.out.println("刘德华睡觉");
    }

    @Override
    public void drink() {
        System.out.println("刘德华喝水");
    }

    @Override
    public void sing() {
        System.out.println("刘德华唱歌");
    }

    @Override
    public void playBall() {
        System.out.println("刘德华能打球吗?");
    }
}

class SportStar implements Star {

    @Override
    public void eat() {
        System.out.println("李宁吃饭");
    }

    @Override
    public void sleep() {
        System.out.println("李宁睡觉");
    }

    @Override
    public void drink() {
        System.out.println("李宁喝水");
    }

    @Override
    public void sing() {
        System.out.println("李宁能唱歌吗?");
    }

    @Override
    public void playBall() {
        System.out.println("李宁打球");
    }
}

interface Star {
    void eat();

    void sleep();

    void drink();

    void sing();

    void playBall();
}

2. Interface Segregation Principle

  • 不同功能类型的接口,应该将大接口拆开若干个小的接口
  • 通过一个类来继承公共的接口和各自类型的接口
package com.design.pattern.day01;

public class Demo03 {
    public static void main(String[] args) {
        // 不同功能的接口,应该将大的接口拆开若干个小的接口
    }
}

class SportStarManager {
    private SportStar sportStar;

    public SportStarManager(SportStar sportStar) {
        this.sportStar = sportStar;
    }

    public void dailyWork() {
        sportStar.drink();
        sportStar.eat();
        sportStar.sleep();
        sportStar.playBall();
    }
}

class SingerStarManager {
    private SingerStar singerStar;

    public SingerStarManager(SingerStar singerStar) {
        this.singerStar = singerStar;
    }

    public void dailyWork() {
        singerStar.sing();
        singerStar.drink();
        singerStar.sleep();
        singerStar.eat();
    }
}

class SingerStar implements Star, SingerStartInter {

    @Override
    public void eat() {
        System.out.println("刘德华吃饭");
    }

    @Override
    public void sleep() {
        System.out.println("刘德华睡觉");
    }

    @Override
    public void drink() {
        System.out.println("刘德华喝水");
    }

    @Override
    public void sing() {
        System.out.println("刘德华唱歌");
    }

}

class SportStar implements Star, SportStarInter {

    @Override
    public void eat() {
        System.out.println("李宁吃饭");
    }

    @Override
    public void sleep() {
        System.out.println("李宁睡觉");
    }

    @Override
    public void drink() {
        System.out.println("李宁喝水");
    }

    @Override
    public void playBall() {
        System.out.println("李宁打球");
    }
}

interface SportStarInter {
    void playBall();
}

interface SingerStartInter {
    void sing();
}

interface Star {
    void eat();

    void sleep();

    void drink();
}

三、Dependence Inversion Principle

  • 高层模块不应该依赖低层模块,二者都应该依赖抽象类
  • 抽象不应该依赖细节,细节应该依赖抽象
  • 中心思想:面向接口编程
  • 抽象的(抽象类或接口)相比细节(实现类)要稳定
  • 接口或者抽象类:提前指定好规范,不涉及具体操作,具体操作由实现类

1. 传统方式

package com.design.pattern.day01;

public class Demo04 {
    /**
     *  如果要增进新的通讯方式
     *  1. 添加新的通讯类
     *  2. 执行类中添加新的方法
     *  3. 客户端不能定义其他的通讯方式
     */
}

class SendService {
    public void sendEmail(Email email) {
        email.contactCustomer();
    }

    public void sendPush(Push push) {
        push.contactCustomer();
    }

    public void sendSms(Sms sms) {
        sms.contactCustomer();
    }
}

class Email {
    public void contactCustomer() {
        System.out.println("email to contact customer");
    }
}

class Push {
    public void contactCustomer() {
        System.out.println("push to contact customer");
    }
}

class Sms {
    public void contactCustomer() {
        System.out.println("sms to contact customer");
    }
}

2. 改进方式

package com.design.pattern.day01;

public class Demo04 {
    /**
     *  如果要增进新的通讯方式
     *  1. 添加新的通讯类
     *  2. 执行类中添加新的方法
     *  3. 客户端不能定义其他的通讯方式
     */
}

class SendService {
    public void sendEmail(Email email) {
        email.contactCustomer();
    }

    public void sendPush(Push push) {
        push.contactCustomer();
    }

    public void sendSms(Sms sms) {
        sms.contactCustomer();
    }
}

class Email {
    public void contactCustomer() {
        System.out.println("email to contact customer");
    }
}

class Push {
    public void contactCustomer() {
        System.out.println("push to contact customer");
    }
}

class Sms {
    public void contactCustomer() {
        System.out.println("sms to contact customer");
    }
}

3. 依赖注入方式

  • 依赖倒置原则(Dependency Inversion Principle)提供了降低模块间耦合度的一种思路
  • 依赖注入(Dependency Injection)是一种具体的实施方法
3.1 接口参数传递
public class Demo04 {
    public static void main(String[] args) {
        new SendService().send(new Sms());
        new SendService().send(new Email());
        new SendService().send(new Push());
        new SendService().send(() -> System.out.println("other way to contact customer"));
    }
}

class SendService {

    public void send(CommunicateTools tool) {
        tool.contactCustomer();
    }
}
3.2 构造器
class SendService {

    private CommunicateTools tool;

    // 构造器注入
    public SendService(CommunicateTools tool) {
        this.tool = tool;
    }

    public void send() {
        tool.contactCustomer();
    }

}
3.3 setter方法
public class Demo04 {
    public static void main(String[] args) {
        SendService pushService = new SendService();
        pushService.setTool(new Push());
        pushService.send();

        SendService emailService = new SendService();
        emailService.setTool(new Email());
        pushService.send();

        SendService smsService = new SendService();
        smsService.setTool(new Sms());
        pushService.send();

        SendService other = new SendService();
        other.setTool(() -> System.out.println("其他方式联系客户"));
        other.send();
    }
}

class SendService {

   // 通过set方法注入
    private CommunicateTools tool;

    public void setTool(CommunicateTools tool) {
        this.tool = tool;
    }

    public void send() {
        tool.contactCustomer();
    }
}

四、Liskov Substitution Principle

  • 使用基类的地方,必须能够透明的使用子类
  • 方式:子类中尽量不要重写父类的方法
  • 继承时,子类无意识的重写父类方法,使得继承体系脆弱,一般是将两个类的公共部分抽取成更高层,然后让这两个类通过聚合,组合等实现

1. 子类重写父类

package com.day.dreamer.seven.liskvo;

public class TraditionalLiskvo {
    public static void main(String[] args) {
        Animal animal = new Animal();
        animal.eat();

        /**
         * 由于子类无意识情况下
         * 重写了父类的方法,因此调用的时候用的是子类的方法
         */
        Cat cat = new Cat();
        cat.eat();
    }
}

class Animal{
    public void eat(){
        System.out.println("动物吃食物");
    }
}

class Cat extends Animal{
    /**
     * 子类中无意识的情况下,将父类的方法进行了重写
     */
    public void eat(){
        System.out.println("猫吃鱼");
    }
}

2. Extract改进

package com.day.dreamer.seven.liskvo;

public class ImprovedLiskvo {
    public static void main(String[] args) {
        Cycle cycle = new Cycle();
        cycle.function();

        Bicycle bicycle = new Bicycle(cycle);
        bicycle.function();
    }
}

/**
 * 将此类提为基类,然后下面两个类脱离继承关系
 */
class Base{
    public void work(){
        System.out.println("测试方法");
    }
}

class Cycle extends Base{
    public void function(){
        System.out.println("交通工具:正常使用");
    }
}

class Bicycle extends Base{
    private Cycle cycle;

    /**通过组合的方式来进行*/
    public Bicycle(Cycle cycle){
        this.cycle = cycle;
    }

    public void function(){
        cycle.function();
        System.out.println("自行车:正常使用");
    }
}

五、Open Close Principle

  • 一个类/方法,对修改关闭(consumer),对扩展(provider)开放。抽象搭建架构,实现做具体事情
  • 对provider而言,新的功能,最好通过扩展而不是修改的方式实现,这样就不需要测试之前代码
  • 其他所有设计原则,设计模式,最终就是要达到开放扩展模式
  • 说白了:面向接口编程

1. 传统方式

package com.design.pattern.day01;

/**
 * 如果增加新的类型,则
 * 1.  增加新的类
 * 2.  新的画图的方法
 * 3.  修改原来的drawShape代码
 */

public class Demo06 {
    public static void main(String[] args) {
        DrawShape tool = new DrawShape();
        tool.drawShape(new Square());
        tool.drawShape(new Triangle());
    }
}

class DrawShape {

    public void drawShape(Shape shape) {
        if (shape.type == 1) {
            drawSquare();
        } else if (shape.type == 2) {
            drawTriangle();
        }
    }

    public void drawSquare() {
        System.out.println("画正方形");
    }

    public void drawTriangle() {
        System.out.println("画三角形");
    }
}

class Square extends Shape {

    private int squareType = 1;

    public Square() {
        super.type = squareType;
    }
}

class Triangle extends Shape {

    private int triangleType = 2;

    public Triangle() {
        super.type = triangleType;
    }
}

class Shape {
    public int type;
}

2. 改进-基于接口

package com.design.pattern.day01;

public class Demo06 {
    public static void main(String[] args) {
        DrawShape tool = new DrawShape();
        tool.drawShape(new Triangle());
        tool.drawShape(new Square());

        // 自定义新的
        tool.drawShape(new Shape() {
            @Override
            public void draw() {
                System.out.println("画其他图形");
            }
        });
    }
}

class DrawShape {

    public void drawShape(Shape shape) {
        shape.draw();
    }


}

class Square implements Shape {


    @Override
    public void draw() {
        System.out.println("画正方形");
    }
}

class Triangle implements Shape {

    @Override
    public void draw() {
        System.out.println("画三角形");
    }
}

interface Shape {
    void draw();
}

六、Demeter Principle

  • 一个对象应该对其他对象保持最少的了解
  • 一个类应该尽可能对外少暴露信息
  • 陌生的类,应该通过成员变量,方法参数,方法返回值,而不是局部变量出现在当前类中

七、Composite Reuse Principle

  • 尽量使用合成/聚合的方式,而不是继承
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值