开闭原则coding

package com.learn.design.principle.openclose;/*** 课程* 他是一个接口* 接口我们最好是以i开头* 正常来说一个课程它是一个实体* 我们可以去写一个类* 有id,name,price三个成员变量* 但是我们是为了演示开闭原则* 因为开闭原则比较抽象* 我们这个例子是相对比较简单的例子* 通过后序的一套课程* 我们会对开闭原则理解更深入* 那我们的课程有很多类型* 有JAVA的* 有算法的* 也有前端的* * 首先回到我们的接口* 首先我们修改了这个接口* 但是我们的接口是不应该经常变化的* 他应该是稳定且可靠的* 否则接口作为契约的效果也就失去了* 那我们再换一种思路* * 为什么一开始的Course是一个接口* 这里是为了演示面向接口编程* * 首先接口没有变* * * @author Leon.Sun**/
public interface ICourse {/*** 这个接口可以返回课程的id* @return*/Integer getId();/*** 课程里面还有name* 课程的名字* 这个也是一个方法* * @return*/String getName();/*** 他里面还有一个价格* * 这里获取原价* * @return*/Double getPrice();/*** 这里获取打折的价格* 我们把这个方法去掉* * @return*/
//    Double getDiscountPrice();}
package com.learn.design.principle.openclose;/*** 我们创建一个类叫JavaCourse* 他实现了ICourse接口* 然后我们来实现这些方法* 那这个实现就比较简单* * 然后这个类也进行了实现* 那假设我们的课程类型很多* 那所有的课程实现类都要实现一下这个方法* 那如果类少我们也就忍了* * 然后我们继续来看这个类* 我们如果通过JavaCourse来写JAVA的一个子类* 我们来试一下* 我们新建一个类* * 他的实现类也没有变* * @author Leon.Sun**/
public class JavaCourse implements ICourse{/*** 声明ID* */private Integer Id;/*** 声明名字* */private String name;/*** 声明他的价格* */private Double price;/*** 声明一个全参构造器* 全部选择* * @param id* @param name* @param price*/public JavaCourse(Integer id, String name, Double price) {/*** 其实这个环境this加不加都是一样的* */this.Id = id;this.name = name;this.price = price;}public Integer getId() {return this.Id;}public String getName() {return this.name;}public Double getPrice() {/*** 我们在这里直接乘以0.8* 看似更简单的完成这个需求* 这次只修改一个类* 我说的只修改一个类* 跟之前方法的两个类* 是相对值* 如果我们的课程还有前端的课程* 还有算法课程* 还有python课程* 那他修改的是一个实现类的个数* 但是有一点是否满足需求呢* 假设需求说我还要显示原价* 这个方法是获取不到原价的* 那再往复杂了说* 如果我们课程大于300元的* 才进行打八折活动呢* 后续再引入优惠券* 所以这个方式我们获取不到原价* */return this.price*0.8;}/*** 那我们的JavaCourse类要进行修改了* 至少我要实现这个方法* 假设现在做活动打八折* 乘以0.8* 看起来我们的需求完成了* 但是我们这种写法我们来看一下* * 这边也不用实现了* * * */
//	@Override
//	public Double getDiscountPrice() {
//		return this.price*0.8;
//	}}
package com.learn.design.principle.openclose;/*** JavaDiscountCourse他来继承JavaCourse* JavaCourse里面没有默认的构造器* 我们在JavaCourse这里并没有一个无参的构造器* 但是那个不重要* 我们还是以课程的目标为准* 这里为什么要命名JavaDiscountCourse* 因为这是一个Java打折的课程* 那如果我们的这个折扣非常的简单* 所有类型的课程都打折* 那我们就可以不叫JavaDiscountCourse* 直接叫做DiscountCourse* 打折的一个课程即可* * 然后我们来声明一个子类来继承JavaCourse* * 虚线的是实现接口* 实线的是继承* 而子类的构造器是调用父类的构造器* 下边的是方法* 一个是返回值是double的* originPrice* 还有一个是返回值的getPrice* 那我们现在的打折销售也完成了* 我们修改的是比较偏应用级的代码* 也就是在应用层的* 而底层的接口* 和底层的基类* 并没有修改* 这样也防止了风险的扩散* 接口里面有很多的方法* 实现类里面逻辑也比较复杂* 那如果我们改折后价的话* 有可能会修改里面的实现* 这个在开发里面都是容易引起bug的* 而我们通过继承了一个基类* 使我们对于扩展是开放的* 而对于修改接口和基类是关闭的* 那我们变化的都是应用层的一个子模块* 比如Test和新增了一个子类* 他影响的范围是越大的* 越高层的影响的范围就越小* 简单的理解* 如果dao层里面变化了* 而这个DAO层被所有service引用* 再上层就是controller* 这个影响就非常大* 有可能我为了改A模块* 所以我们在面向对象编程的时候* 我们一定要强调开闭原则* 其他原则也是开闭原则的一个具体形态* 首先它提高我们的复用性* 而且提高了可维护性* 因为我们并不是一个人单打独斗* 我们要考虑软件的维护成本* 一个典型的例子就是Spring容器* 提供的控制反转* 比如我们会注入一些对象* 来修改源码的一些内容* 就是把控制通过配置文件* 或者bean的配置方式* 而不是去修改Spring的源码* 例如我们通过Spring的特性* 来完成单表登陆的功能* 如果你们团队都遵循开闭原则* 我们的软件项目以后维护起来也会非常容易的* 成本也会非常低* 我通过这个例子简单的介绍一下* 开闭原则* 现在体会不深不要紧* 后续很多的设计模式不断地加强巩固* 那随着我们课程的学习* 大家对这几个原则理解也会越来越深的* 有些设计模式和原则会有冲突* 那其实就是一个平衡的问题* 这个后面再碰到我会详细说的* * * * @author Leon.Sun**/
public class JavaDiscountCourse extends JavaCourse {public JavaDiscountCourse(Integer id, String name, Double price) {/*** IDEA默认给的就是这个*/super(id, name, price);}/*** 从名字上来看* 获取原价* * @return*/public Double getOriginalPrice(){return super.getPrice()*0.8;}/*** 我们复写父类的一个方法* * 我们还是回到这个类里面* * * @return*/public Double getDiscountPrice(){/*** 默认生成的是super.getPrice()* 也就是要调用父类的getPrice方法* 这里面直接乘以0.8* 如果我们这里要做分区间的折扣* 当前的价格大于200的时候* 我们可以打九折* 大于300我们打八折* 这里面我们就直接打折8折* 在这个地方留了一个伏笔* 后边里氏替换原则的时候* 还会回来讲一下这里* * */return super.getPrice()*0.8;}}
package com.learn.design.principle.openclose;/*** 现在我们有一个测试函数* * 我们现在来看一下类结构图* 现在的类结构图非常的简单* ICourse这个是一个接口* JavaCourse这里是一个类* 这个类实现这个接口* 非常清晰* 我们一定要善用IDEA里面的查看工具* 在我们看源码的时候非常有用* 这里和标准的UML有一点小小的差异* 比如I就代表Interface* 也没有用尖括号* 我们能看出来* 这个是他的类型* 现在的类结构也是非常的简单* 我们也输出了信息* 双十一和618要进行一个打折活动* 那我们怎么来开发这个需求呢* * 现在我们回到test里面* * * * * @author Leon.Sun**/
public class Test {public static void main(String[] args) {/*** 我们通过一个接口指向实体类* 第一门课程的ID是96* 名字是"Java从零到企业级电商开发"* 价格是348元* * 这个实现类就是JavaDiscountCourse* JAVA的折扣课程* 课程ID:96 课程名称:Java从零到企业级电商开发 课程原价:278.40000000000003 课程折后价格:222.72000000000003元* 结果出来了* 这里是因为Doble丢失精度的问题* 通过BigDecimal的String构造器* 对于BigDecimal要注意使用String构造器* 那这个不是我们课程的重点* 通过BigDecimal就能够解决他* 那么我们现在接着回来* * 他是一个接口* 对象来指向一个实例* 也可以理解成一个子类的实例* JavaDiscountCourse这个类继承了JavaCourse类* JavaCourse类又实现了ICourse类* 可以简单地理解* 所以实现是JavaDiscountCourse* 但是他的引用是ICourse* 所以我们在这里面想获取原价的时候* 并没有getOriginalPrice* 那我们怎么办啊* 很简单* 我们debug来看一下* 我们看一下JavaDiscountCourse这个类* 我们看到他的类型就是JavaDiscountCourse* 因为我们是使用父类的引用* 所以他拿不到那个pulic方法* * */ICourse iCourse = new JavaDiscountCourse(96, "Java从零到企业级电商开发", 348d);/*** 我们对他直接进行强转* 这样我们就强转成功了* */JavaDiscountCourse javaCourse = (JavaDiscountCourse) iCourse;/*** 然后我们直接输出* System.out.println这个在实际项目中是禁止的* 因为在System.out里面是有锁的* 现在只是一个调试讲解设计模式* 我们就不引入log包了* 就用System.out调试理解即可* 首先是课程ID javaCourse.getId()* 然后呢课程的名称javaCourse.getName()* 然后是课程的价格javaCourse.getPrice()* 单位是元* 课程ID:96 课程名称:Java从零到企业级电商开发 课程原价:348.0 课程折后价格:278.40000000000003元* 现在我们的课程信息都正常输出了* * 课程价格和折扣价格* 现在是直接通过getPrice()拿到的* 那我们的原价没有了* * 课程折后价格* 课程原价还是javaCourse.getOriginalPrice()* */System.out.println("课程ID:" + javaCourse.getId() + " 课程名称:" + javaCourse.getName() + " 课程原价:" + javaCourse.getPrice() + " 课程折后价格:" + javaCourse.getDiscountPrice() + "元");}
}

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部