设计模式第一回

本文介绍了UML中的类图、时序图及其元素,并通过一个课程设计的例子阐述了面向抽象编程的开闭原则。在课程接口的基础上,讨论了当需要新增打折功能时,如何通过扩展而非修改原有代码来遵循开闭原则,从而提高软件的可复用性和可维护性。
摘要由CSDN通过智能技术生成

一 UML

1.1 UML Class

1.1 子类指向父类

在这里插入图片描述

1.2 实现继承、虚线实现

在这里插入图片描述

在这里插入图片描述

1.3 实现关联,虚线依赖

在这里插入图片描述

在这里插入图片描述

虚线:
在这里插入图片描述

实线:
在这里插入图片描述

1.4 空心菱形-聚合 实心菱形-组合

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.5 案例

在这里插入图片描述

1.2 UML时序图

在这里插入图片描述

在这里插入图片描述

二 设计原则

设计原则:

  • 开闭原则

  • 依赖倒置原则

  • 单一职责原则

  • 接口隔离原则

  • 迪米特法则(最少知道原则)

  • 里氏替换原则

  • 合成、复用原则(组合、复用原则)

    2.1 开闭原则

    一个软件实体如类,模块或者函数应该对扩展开放,对修改关闭(开闭)。强调的是用抽象构建框架,用实现扩展细节。按照这个原则的优点就是提高软件的可复用性和可维护性。----面向抽象编程。

举例有个课程的设计,面向抽象编程首先课程定义成接口,课程有获取课程id,课程名称,课程价格的三个抽象方法

public interface ICourse {

    public Integer getId();
    public String getName();
    public Double getPrice();

}

针对课程,可能会有Java课程,Go课程,PHP课程等等,因此我们会有不同的子类实现

package designpatterns.principle.openclose;

public class JavaCourse  implements ICourse{

    private int id;
    private String name;
    private double price;

    public JavaCourse(int 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;
    }
}
package designpatterns.principle.openclose;

public class GoCourse implements ICourse{

    private int id;
    private String name;
    private double price;

    public GoCourse(int 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;
    }
}

在这里插入图片描述

我们编写一个测试类,来获取某个具体课程的名称,价格等:

package designpatterns.principle.openclose;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import static org.junit.Assert.*;

@Slf4j
public class ICourseTest {

    @Test
    public void testCourse() {

        ICourse iCourse = new JavaCourse(1001, "java 编程学习", 320);

        log.info("课程id {}, 课程名称{}, 课程价格{}", iCourse.getId(), iCourse.getName(), iCourse.getPrice());

    }
}

假如这时候这时候我们需要一个活动,比如双十一 618等等,这时候价格有一个打折的价格。那么应该怎么做?

一种方法我们通过修改接口,增加一个getDiscountPrice(), 但是接口一般是稳定的,不应该有大动作改动,这会带来一个问题,就是我们的所有这个接口的实例比如JavaCourse,GoCourse 都需要更改逻辑增加这样的一个方法,这就破坏了我们的开闭原则。那么我们还能怎么做呢?
定义一个新的子类,继承自JavaCourse,这时候我们就不需要改动Course接口,也不需要改动avaCourse,GoCourse,这样我们就做到了对扩展开放,对修改关闭。

package designpatterns.principle.openclose;

public class JavaDiscountCourse  extends JavaCourse{
    public JavaDiscountCourse(int id, String name, double price) {
        super(id, name, price);
    }


    public Double getOriginPrice() {
        return super.getPrice();
    }

    @Override
    public Double getPrice() {
        return super.getPrice() * 0.8;
    }
}

测试类调整如下:

package designpatterns.principle.openclose;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import static org.junit.Assert.*;

@Slf4j
public class ICourseTest {

    @Test
    public void testCourse() {

        ICourse iCourse = new JavaCourse(1001, "java 编程学习", 320);

        log.info("课程id {}, 课程名称{}, 课程价格{}", iCourse.getId(), iCourse.getName(), iCourse.getPrice());

    }

    @Test
    public void testCourseDiscount() {

        ICourse iCourse = new JavaDiscountCourse(1001, "java 编程学习", 320);

        JavaDiscountCourse javaDiscountCourse = (JavaDiscountCourse)iCourse;
        log.info("课程id {}, 课程名称{}, 原始课程价格{},打折之后的价格", iCourse.getId(), iCourse.getName(), ((JavaDiscountCourse) iCourse).getOriginPrice(), iCourse.getPrice());

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值