网站首页 > 精选教程 正文
更多java文章与项目资源、毕业设计、福利
关注公众号 程序猿forever
软件设计七大原则
3-1 本章导航
3-2 开闭原则讲解
实现开闭原则的核心思想就是面向抽象编程而不是面向具体的实现编程。
3-3 开闭原则coding
- 首先定义一个课程的接口:
public interface ICourse {
Integer getId();
String getName();
Double getPrice();
}
12345
- 定义一个Java课程的类并且实现课程接口:
public class JavaCourse implements ICourse {
private Integer id;
private String name;
private Double price;
public JavaCourse(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;
}
}
1234567891011121314151617181920212223242526
- 定义一个Test测试类:
public class Test {
public static void main(String[]args){
ICourse javaCourse = new JavaCourse(96, "Java 从零开始到企业级开发", 348d);
System.out.println("课程Id:" + javaCourse.getId() + "课程名称:" + javaCourse.getName() + "课程价格:" + javaCourse.getPrice());
}
}
123456
输出结果如下:
课程Id:96课程名称:Java 从零开始到企业级开发课程价格:348.0
现在的类结构图如图所示:
假如现在双十一的时候,要进行课程的打折活动:我们应该如何去做呢 ?
我们可以这样来做:
添加一个计算打折价格的方法:
public interface ICourse {
Integer getId();
String getName();
Double getPrice();
Double getDiscountPrice();
}
123456
同样实现类也要实现这个方法:
public class JavaCourse implements ICourse {
private Integer id;
private String name;
private Double price;
public JavaCourse(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 Double getDiscountPrice() {
return this.price*0.8;
}
}
12345678910111213141516171819202122232425262728293031
在Test类里面,我们就是可以这样来进行获取:
public class Test {
public static void main(String[]args){
ICourse javaCourse = new JavaCourse(96, "Java 从零开始到企业级开发", 348d);
System.out.println("课程Id:" + javaCourse.getId() + "课程名称:" + javaCourse.getName() + "课程价格:" + javaCourse.getPrice()+"双十一打折价格:"+javaCourse.getDiscountPrice());
}
}
123456
输出结果如下:
课程Id:96课程名称:Java 从零开始到企业级开发课程价格:348.0双十一打折价格:278.40000000000003
但是,这种方法不好,假如课程很多,那么所有的课程的实现类都要重写一下方法,接口应该是稳定的,不应该是经常修改的。
我们再换一种方法:
我们写一个Java课程打折类并且继承于Java课程类,之前的课程类里面的价格就不打折了:
public class JavaDiscountCourse extends JavaCourse {
public JavaDiscountCourse(Integer id, String name, Double price) {
super(id, name, price);
}
@Override
public Double getPrice() {
return super.getPrice()*0.8;
}
}
12345678910
然后,我们在测试的时候,就是可以直接指向Java课程打折类的这个对象就可以了:
public class Test {
public static void main(String[]args){
ICourse javaCourse = new JavaDiscountCourse(96, "Java 从零开始到企业级开发", 348d);
System.out.println("课程Id:" + javaCourse.getId() + "课程名称:" + javaCourse.getName() + "课程价格:" + javaCourse.getPrice());
}
}
123456
这个时候的结果就是:这里有丢失精度的问题,可以使用String构造器的BigDecimal来解决
课程Id:96课程名称:Java 从零开始到企业级开发课程价格:222.72000000000003
如果我们还想要原价,我们可以这样来做:
public class JavaDiscountCourse extends JavaCourse {
public JavaDiscountCourse(Integer id, String name, Double price) {
super(id, name, price);
}
/** 获取原价的方法 */
public Double getOriginPrice() {
return super.getPrice();
}
@Override
public Double getPrice() {
return super.getPrice()*0.8;
}
}
1234567891011121314
这个时候,我们就是可以这样来调用:
public class Test {
public static void main(String[]args){
ICourse iCourse = new JavaDiscountCourse(96, "Java 从零开始到企业级开发", 348d);
/** 如果调用实现类里面的方法,我们就必须要进行强转一下 */
JavaDiscountCourse javaCourse = (JavaDiscountCourse)iCourse;
System.out.println("课程Id:" + javaCourse.getId() + "课程名称:" + javaCourse.getName() + "课程价格:"+javaCourse.getOriginPrice()+"课程折后价格:" + javaCourse.getPrice());
}
}
12345678
执行结果如下:
课程Id:96课程名称:Java 从零开始到企业级开发课程价格:348.0课程折后价格:278.40000000000003
现在的类图如图所示:
我们通过了继承了基类,然后对其进行扩展,对扩展是开发的,而对修改接口和基类是关闭的;
越是基层的模块的修改影响的范围是越大的。
3-4 依赖倒置原则讲解+coding
依赖倒置原则的核心就是:面向接口编程
有一个类:里面有两个方法,一个学习java课程的方法,一个是学习FE课程的方法:
public class Tom {
public void studyJavaCourse() {
System.out.println("Tom在学习Java课程");
}
public void studyFECourse() {
System.out.println("Tom在学习FE课程");
}
}
12345678
这个时候,我们写上一个测试类:
public class Test {
public static void main(String[]args){
Tom tom = new Tom();
tom.studyJavaCourse();
tom.studyFECourse();
}
}
1234567
如果这个时候,我还想要添加一个学习Python课程的方法,这个时候,我可以在基类里面进行添加方法:
public class Tom {
public void studyJavaCourse() {
System.out.println("Tom在学习Java课程");
}
public void studyFECourse() {
System.out.println("Tom在学习FE课程");
}
public void studyPythonCourse() {
System.out.println("Tom在学习Python课程");
}
}
1234567891011
以上我们的做法就是在面向实现来进行编程,面向实现类来进行编程的话, 扩展性比较的差,这个就是依赖于底层的实现的
现在我们来引入抽象来解决这个问题:
public interface ICourse {
void studyCourse();
}
123
public class JavaCourse implements ICourse {
@Override
public void studyCourse() {
System.out.println("Tom在学习Java课程");
}
}
123456
public class FECourse implements ICourse {
@Override
public void studyCourse() {
System.out.println("Tom在学习FE课程");
}
}
123456
原来的Tom类,我们就要进行重构了,写了一个学习课程的方法,传入了学习课程的接口,由具体的实现类来进行实现:
具体学了哪些课程,是由具体的实现类来决定的:
public class Tom {
public void studyCourse(ICourse iCourse) {
iCourse.studyCourse();
}
}
12345
我们对其进行测试:
public class Test {
public static void main(String[]args){
Tom tom = new Tom();
tom.studyCourse(new JavaCourse());
tom.studyCourse(new FECourse());
}
}
1234567
执行结果为:
Tom在学习Java课程
Tom在学习FE课程
这个时候,如果还要学习Python的课程的话,那我们就可以再写上一个实现类来对接口进行实现即可:
public class PythonCourse implements ICourse {
@Override
public void studyCourse() {
System.out.println("Tom在学习Python课程");
}
}
123456
我们就可以来调用了:
public class Test {
public static void main(String[]args){
Tom tom = new Tom();
tom.studyCourse(new JavaCourse());
tom.studyCourse(new FECourse());
tom.studyCourse(new PythonCourse());
}
}
12345678
输出结果:
Tom在学习Java课程
Tom在学习FE课程
Tom在学习Python课程
以上是通过接口方法的方式来注入具体的实现;
当然,我们也可以通过构造器的方式来注入具体的实现:
在Tom这个类里面写一个构造器,把接口作为Tom类里面的一个成员属性,然后通过构造器来对其进行赋值:
public class Tom {
private ICourse iCourse;
public Tom(ICourse iCourse) {
this.iCourse = iCourse;
}
/** 这里的方法,就只需要调用类成员变量ICourse里面的studyCourse()方法就可以了 */
public void studyCourse() {
iCourse.studyCourse();
}
}
1234567891011
测试:
public class Test {
public static void main(String[]args){
Tom tom = new Tom(new JavaCourse());
tom.studyCourse();
}
}
123456
测试结果:
Tom在学习Java课程
以上的用构造器来进行传递接口的实现,也不是很好,每次学一个新的课程的时候,还有重新new一个类;
这个时候,我们可以利用set方法来进行注入:
public class Tom {
private ICourse iCourse;
public void setiCourse(ICourse iCourse) {
this.iCourse = iCourse;
}
public void studyCourse() {
iCourse.studyCourse();
}
}
1234567891011
这个时候,我们就是可以这样来用了:
public class Test {
public static void main(String[]args){
Tom tom = new Tom();
tom.setiCourse(new JavaCourse());
tom.studyCourse();
tom.setiCourse(new FECourse());
tom.studyCourse();
}
}
12345678910
执行结果:
Tom在学习Java课程
Tom在学习FE课程
现在的类图:
猜你喜欢
- 2024-11-02 Java,设计模式,七大原则,里氏替换原则(LSP),案例
- 2024-11-02 设计模式七大原则 设计模式七大原则包括
- 2024-11-02 Java设计模式的精神领袖:开闭原则
- 2024-11-02 设计模式第2招第3式之命令模式 命令模式定义
- 2024-11-02 Java代码优化六大原则 java代码优化六大原则有哪些
- 2024-11-02 一天一个设计模式——软件架构设计七大原则
- 2024-11-02 专门画了9张图,搞懂设计模式6大原则,这次应该可以了吧
- 2024-11-02 程序员应知道这十大面向对象设计原则
- 2024-11-02 3张图说清楚:java设计模式原则:开闭、接口隔离、迪米特法则
- 2024-11-02 Java 设计原则与思想:高内聚和低耦合
你 发表评论:
欢迎- 04-11Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- 04-11Java中你知道几种从字符串中找指定的字符的数量
- 04-11探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- 04-11Python字符串详解与示例(python字符串的常见操作)
- 04-11java正则-取出指定字符串之间的内容
- 04-11String s1 = new String("abc");这句话创建了几个字符串对象?
- 04-11java判断字符串中是否包含某个字符
- 04-11关于java开发中正确的发牌逻辑编写规范
- 最近发表
-
- Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- Java中你知道几种从字符串中找指定的字符的数量
- 探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- Python字符串详解与示例(python字符串的常见操作)
- java正则-取出指定字符串之间的内容
- String s1 = new String("abc");这句话创建了几个字符串对象?
- java判断字符串中是否包含某个字符
- 关于java开发中正确的发牌逻辑编写规范
- windows、linux如何后台运行jar(并且显示进程名)
- 腾讯大佬私人收藏,GitHub上最受欢迎的100个JAVA库,值得学习
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)