【设计模式】软件设计原则——开闭原则&里氏替换&单一职责

开闭原则内容引出

开闭原则

定义: 一个软件实体,类,函数,模块;对扩展开放 ,对修改关闭。用抽象构建框架,用实现扩展细节。可以提高软件的可复用性和可维护性。

开发新功能时,尽量不修改原有代码,尽量使用扩展来增加新功能。

实现开闭原则的核心思想 是:面向抽象编程,而不是面向实现编程。

定义的对象类型是:抽象or接口;调用的是抽象类or接口中的方法。抽象是稳定的,让一个类依赖于抽象,实现对修改关闭。再通过面向对象的继承 与**多态,**实现对抽象的继承,通过重写方法or实现新的扩展方法。

开闭原则示例

java 复制代码
/**
 * 商品接口
 */
public interface IGood {
    Integer getId();
    String getName();
    Double getPrice();
}
java 复制代码
/**
 * 普通商品
 */
public class NormalGood implements IGood {
    private Integer id;
    private String name;
    private Double price;

    public NormalGood(Integer id, String name, Double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    @Override
    public Integer getId() {
        return this.id;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public Double getPrice() {
        return this.price;
    }

    @Override
    public String toString() {
        return "...普通商品信息"
    }
}
java 复制代码
/**
添加打折功能
根据开闭原则 , 对修改关闭 , 对扩展开放;
定义子类,在继承普通商品的基础上,扩展的新功能;
不用实现接口,而是继承普通类。
站在会员卡角度如下:
card接口;普通用户类;银卡继承普通用户;金卡继承银卡
*/
public class DiscountGood extends NormalGood {

    public DiscountGood(Integer id, String name, Double price) {
        super(id, name, price);
    }

    @Override
    public Double getPrice() {
        return super.getPrice() * 0.8;//折扣位置
    }
}

里氏替换原则

子类可以扩展父类的功能,但不能改变父类原有的功能。

是开闭原则的重要方式之一,由于使用父类对象的地方都可以使用子类对象,因此在程序中尽量使用父类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

java 复制代码
public class FatherClass {
    public void method(HashMap map) {
        System.out.println("执行父类 void method(HashMap map) 方法");
    }
}

public class ChildClass extends FatherClass {
    /**
     * 重写
     * 重写 ( 返回值 严格 ) : 当 子类的方法 重写 / 重载 / 实现 父类的方法时
     *      方法的 后置条件 ( 返回值 ) 要 比父类更严格或相等;
     */
    @Override
    public void method(HashMap map) {
        System.out.println("执行子类重写的 void method(HashMap map) 方法");
    }

    /**
     * 重载
     * 重载 ( 输入参数 宽松 ) : 子类的方法 重载 父类的方法 时
     *      方法的前置条件 ( 输入参数 ) , 要比 父类方法的输入参数更宽松 ;
     *
     * 如果在父类中参数类型是 Map
     *      在子类中重载参数类型是 HashMap
     *      这样就会出现混乱的问题
     * 客户端调用时 , 可能不清楚情况 , 加入传入了 HashMap 参数
     *      此时就有可能出现混乱 , 无法调用到 父类/子类的 正常重写方法
     *      方法调用被重载方法拦截的情况
     *
     * 如果 重载的方法 的参数 比父类的方法参数更严格
     *      那么这就不是重载方法 , 而是重写方法
     */
    public void method(Map map) {
        System.out.println("执行子类重载的 void method(Map map) 方法");
    }

}

单一职责内容引出

单一职责

定义: 不要存在多余一个导致类变更的原因。

假设有一个类,负责"A"和"B";一旦需求变更,如A功能改变,修改该类A功能时,有可能导致B功能发生故障。对于该情况,应该对于AB各自建立独立的类,保证系统的稳定性。

**开发方法:**一个类只负责一项职责(类、接口、方法)

**优点:**可读性高、提高系统可维护性、降低类的复杂度、降低需求变更导致的风险。

模块化的系统中,都适合使用单一职责。

java 复制代码
//以下代码均违反了单一职责原则
public class Dog{
    public void mainDogs(String name) {
        if ("小狗".equals(name)) {
            System.out.println("puppy's name is "+name);
        } else {
            System.out.println("Dog's name is "+name);
        }
    }
}

//-----------------------------------------------------------------

public class Order {
    private String orderId;
    private String userId;
    private String productId;
    private double amount;
    private OrderStatus status;

    public void createOrder(String userId, String productId, double amount) {
        // 创建订单  
    }

    public void payOrder() {
        // 支付订单  
    }

    public void shipOrder() {
        // 发货 
    }

    public void completeOrder() {
        // 完成订单 
    }
}

类的单一

java 复制代码
/**
 *本类的职责单一,只负责puppy
 */
public class Puppy{
    public void IsPuppy(String name) {
        System.out.println("Puppy's name is "+name);
    }
}
public class Dog{
    public void IsDog(String name) {
        System.out.println("Dogs's name is "+name);
    }
}

//--------------------------------------------------
// 订单接口
public interface Order {
    void create();

    void pay();

    void ship();

    void complete();
}

// 创建类
public class OrderCreator implements Order {
    @Override
    public void create() {
    // 创建订单的业务逻辑
    }
}

...其他业务类


// 订单完成类
public class OrderCompleter implements Order {
    @Override
    public void complete() {
// 完成订单的逻辑
    }
}

方法单一

如果方法中存在大片的if-else说明是不完善的代码,而我们在开发中其实应该避免如is-else或者switch等条件语句。

java 复制代码
//违反单一原则的代码
//如果只针对价格or名字or描述进行修改,会连带修改另外两个,存在一定风险
public class Good {
    public void updateGoodInfo(String name, double price,String description) {
            //更新商品信息逻辑
    }
}


//修改后:
public class Good{
    public void updateGoodName(String Name){
            //修改名字
    }

    public void updateGoodPrice(String Name){
            //修改价格
    }
    public void updateGoodDescription(String Name){
            //修改商品描述
    }

}

接口单一

java 复制代码
public interface IGood {
    //获取名称
    String getName();

    //获取价格
    double getPrice();

    //获取商品描述
    String getDescription();

    //购买
    void buyGood();
}

//-----------------------拆分------------------------
public interface IGoodInfo{//接口1,商品信息接口
    String getName();
    String getDescription();
    double getPrice();
}

public interface IGoodManage{
    void buyGood();//接口2,商品操作接口
    //退换等其他逻辑
}

//商品实现
publci class IGoodImpl implements IGoodInfo,IGoodManage{
    @Override
    //.....
}
相关推荐
小鑫记得努力4 分钟前
Java类和对象(下篇)
java
binishuaio8 分钟前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE10 分钟前
【Java SE】StringBuffer
java·开发语言
老友@10 分钟前
aspose如何获取PPT放映页“切换”的“持续时间”值
java·powerpoint·aspose
wrx繁星点点25 分钟前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式
Upaaui28 分钟前
Aop+自定义注解实现数据字典映射
java
zzzgd81628 分钟前
easyexcel实现自定义的策略类, 最后追加错误提示列, 自适应列宽,自动合并重复单元格, 美化表头
java·excel·表格·easyexcel·导入导出
友善的鸡蛋29 分钟前
解决:使用EasyExcel导入Excel模板时出现数据导入不进去的问题
java·easyexcel·excel导入
星沁城30 分钟前
240. 搜索二维矩阵 II
java·线性代数·算法·leetcode·矩阵
NoneCoder42 分钟前
Java企业级开发系列(1)
java·开发语言·spring·团队开发·开发