重构学习day01 类型码 类型码的上层建筑 与类型码相关的重构方法 1.使用子类代替类型码 2.使用状态或策略模式代替类型码
名词:类型码 类型码的上层建筑 重构方法 1.使用子类代替类型码 2.使用状态/策略模式代替类型码 类中存在方法把某个字段当作条件,根据字段值的不同,进行不同的处理。(自定义概念)
则这个字段叫做:类型码。(重构-改善既有代码的设计中的概念)
这个方法叫做:类型码的上层建筑。(自定义概念)
(这种判断方法不是绝对正确,但是一般可行,类型码是重构-改善既有代码的设计的概念,但是类型码的上层建筑是自定义概念) 例子1:
Movie对象中存在影片类型字段,根据影片类型和租期计算金额的getCharge()方法和计算用户积分的getRentPoints()
getCharge()方法和getRentPoints()都以影片类型字段为条件,进行不同的处理。
所以根据上面的解释:
类型码=影片类型
类型码(影片类型)的上层建筑2个:getCharge()方法和getRentPoints()方法
package refactor; public class Movie {
public static final int NEW_RELEASE = 0;
public static final int REGULAR = 1;
public static final int CHILDREN = 2; private int priceCode;
private String title; public Movie() {
} public Movie(String title, int priceCode) {
this.priceCode = priceCode;
this.title = title;
} public double getCharge(int daysRent){
double result = 0;
switch(priceCode){
case Movie.REGULAR:
result += 2;
if(daysRent > 2){
result += (daysRent - 2) * 1.5;
}
break;
case Movie.NEW_RELEASE:
result += daysRent * 3;
break;
case Movie.CHILDREN:
result += 1.5;
if(daysRent > 3){
result += (daysRent - 3) * 1.5;
}
break;
}
return result;
} public int getRentPoints(int daysRent){
int rentPoints = 1;
if(priceCode == Movie.NEW_RELEASE
&& daysRent > 1){
rentPoints++;
}
return rentPoints;
}
}
Movie直接使用类型码
当影片类型不多,分支逻辑不复杂,上层建筑不多,并且以后变化也不大时,直接使用类型码和使用多态重构区别不太大。 直接使用类型码的问题:
可是随着影片类型的迅速扩张,分支逻辑的复杂性升高,上层建筑的增多,直接使用类型码将导致
1.如果影片类型增加的非常多时,则条件语句将会非常长,并且每个上层建筑都会对应一个这样的条件语句。
2.如果影片类型增加,上层建筑增多,而此时分支逻辑复杂度也很高,则需要为了防止上层建筑过长,需要抽取每个分支逻辑为方法,将可能导致本类方法迅速膨胀。
所以:当影片类型,分支逻辑,上层建筑发生的变化较大时,则直接使用类型码会导致类过大,上层建筑过长或者产生过多的方法,条件语句随着上层建筑重复等问题,
总之就是导致代码难逻辑和结构的越来越不清晰,越来越难理解,越来越难修改,越来越容易出错。 使用重构则是较好的解决方案:
1.replace type code with subclass 对象类型码的值在生命期间不会发生变化
2.replace type code with state/strategy 对象类型码的值可能在生命期间发生变化。
好处:
1.不管原来的上层建筑有多少,重构后,只需要维护一个产生子类或者状态/策略的条件语句。
2.与类型码相关的处理都被放到相应的类中。代码结构和逻辑更清晰。
每个子类(状态/策略)与类型码的值一一对应,每个与类型码值对应的处理逻辑都被放在与该类型码值相对应的子类(状态/策略)中,代码的结构和逻辑非常清晰。
每个子类(状态/策略)与类型码的值一一对应,每个与类型码值对应的处理逻辑都被放在与该类型码值相对应的子类(状态/策略)中,代码的结构和逻辑非常清晰。
每个子类(状态/策略)与类型码的值一一对应,每个与类型码值对应的处理逻辑都被放在与该类型码值相对应的子类(状态/策略)中,代码的结构和逻辑非常清晰。
package shop; public class Movie {
public static final int NEW_RELEASE = 0;
public static final int REGULAR = 1;
public static final int CHILDREN = 2; private String title;
private Price price; public Movie() {
} public Movie(String title, int priceCode) {
setPriceCode(priceCode);
this.title = title;
} public int getPriceCode() {
return price.getPriceCode();
} //有2个上层建筑,但是程序只需要维护一个根据类型码产生state对象的条件语句
public void setPriceCode(int priceCode) {
switch (priceCode){
case Movie.NEW_RELEASE:
price = new NewPrice();
break;
case Movie.REGULAR:
price = new RegularPrice();
break;
case Movie.CHILDREN:
price = new ChildrenPrice();
break;
default:
throw new IllegalArgumentException("非法的影片类型:" + priceCode);
}
} public double getCharge(int daysRent){
return price.getCharge(daysRent);
} public int getRentPoints(int daysRent){
return price.getRentPoints(daysRent);
}
}
Movie使用状态模式重构类型码
package shop;
//子类或状态与类型码一一对应,相应的逻辑也全部集中在这个类中。代码的结构和逻辑更清晰
public class ChildrenPrice extends Price {
@Override
public int getPriceCode(){
return Movie.CHILDREN;
} @Override
public double getCharge(int daysRent) {
double result = 1.5;
if(daysRent > 3){
result += (daysRent - 3) * 1.5;
}
return result;
}
}
ChildrenPrice子类或状态与类型码一一对应
package shop;
//子类或状态与类型码一一对应,相应的逻辑也全部集中在这个类中。代码的结构和逻辑更清晰
public class NewPrice extends Price{
@Override
public int getPriceCode() {
return Movie.NEW_RELEASE;
} @Override
public double getCharge(int daysRent) {
return daysRent * 3;
} @Override
public int getRentPoints(int daysRent) {
return daysRent > 1 ? 2 : 1;
}
}
NewPrice 子类或状态与类型码一一对应
package shop;
//子类或状态与类型码一一对应,相应的逻辑也全部集中在这个类中。代码的结构和逻辑更清晰
public class RegularPrice extends Price {
@Override
public int getPriceCode() {
return Movie.REGULAR;
} @Override
public double getCharge(int daysRent) {
double result = 2;
if(daysRent > 2){
result += (daysRent - 2) * 1.5;
}
return result;
}
}
RegularPrice 子类或状态与类型码一一对应
类型码:类的一个字段,该类中存在方法把这个字段当作条件,根据字段值的不同,进行不同的处理。
类型码的上层建筑:某个方法,根据类型码不同的值进行不同处理。
当类型码的上层建筑有多个,则每个上层建筑都需要维护着条件判断。导致总体上基于类型码的条件判断有多个。
重构方法:
1.replace type code with subclass
2.replace type code with state/strategy
和直接使用类型码的区别:
2个重构手法避免了多个基于类型码的条件判断的产生,使基于类型码的条件判断始终只有一个。
上层建筑通过多态
重构学习day01 类型码 类型码的上层建筑 与类型码相关的重构方法 1.使用子类代替类型码 2.使用状态或策略模式代替类型码的更多相关文章
- Python策略模式实现源码分享
1.让一个对象的某个方法可以随时改变,而不用更改对象的代码 2.对于动态类型的Python语言,不需要定义接口 3.基本的实现方法:用类作为参数传递 例如: 12_eg3.py class Movea ...
- java学习day01之String的特点,如何实现,并且有哪些重要方法?
1.以主流的JDK版本1.8来说,String内部实际存储结构为char数组,源码如下: public final class String implements java.io.Serializa ...
- 第三百四十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—爬虫和反爬的对抗过程以及策略—scrapy架构源码分析图
第三百四十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—爬虫和反爬的对抗过程以及策略—scrapy架构源码分析图 1.基本概念 2.反爬虫的目的 3.爬虫和反爬的对抗过程以及策略 scra ...
- 使用策略模式重构switch case 代码
目录 1.背景 2.案例 3.switch…case…方式实现 4.switch…case…带来的问题 5.使用策略模式重构switch…case…代码 6.总结 1.背景 之前在看<重构 ...
- swift设计模式学习 - 策略模式
移动端访问不佳,请访问我的个人博客 设计模式学习的demo地址,欢迎大家学习交流 策略模式 策略模式定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户. ...
- 项目一:第五天 1、区域数据(pinyin4j-简码,城市编码) 2、Web层代码重构(model对象,分页代码提取) 3、区域分页查询 3、分区添加功能 4、定区管理管理-添加,分页
Service: /** * @Description: 1.保存定区 2.让分区关联定区 * 对象三种状态 1.持久态(被session管理对象-一级缓存中有对象) 2.托管态(有OID标识,数据 ...
- Future模式的学习以及JDK内置Future模式的源码分析
并发程序设计之Future模式 一).使用Future模式的原因 当某一段程序提交了一个请求,期待得到一个答复,但服务程序对这个请求的处理可能很慢,在单线程的环境中,调用函数是同步的,必须等到服务程序 ...
- 与众不同 windows phone (24) - Input(输入)之软键盘类型, XNA 方式启动软键盘, UIElement 的 Touch 相关事件, 触摸涂鸦
原文:与众不同 windows phone (24) - Input(输入)之软键盘类型, XNA 方式启动软键盘, UIElement 的 Touch 相关事件, 触摸涂鸦 [索引页][源码下载] ...
- Netty-主从Reactor多线程模式的源码实现
Netty--主从Reactor多线程模式的源码实现 总览 EventLoopGroup到底是什么? EventLoopGroup是一个存储EventLoop的容器,同时他应该具备线程池的功能. gr ...
随机推荐
- 深入Vue.js从源码开始(二)
从入口开始 我们之前提到过 Vue.js 构建过程,在 web 应用下,我们来分析 Runtime + Compiler 构建出来的 Vue.js,它的入口是 src/platforms/web/en ...
- codeforces 570D.Tree Requests
[题目大意]: 给定一棵树,树的每个节点对应一个小写字母字符,有m个询问,每次询问以vi为根节点的子树中,深度为hi的所有节点对应的字符能否组成一个回文串: [题目分析]: 先画个图,可看出每次询问的 ...
- wav音频文件头解析
wav概述 WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(ResourceInterchange File Format)文件规范,用于保存Windows平台的音频信息 ...
- CSS3学习笔记(3)—左右飞入的文字
前几天看到一个企业招聘的动画觉得很炫,里面有个企业介绍的文字是用飞入的效果做出来的,今天尝试了写了一下,感觉还不错~\(≧▽≦)/~啦啦啦 下面来看我做的动态效果: 其实上面的效果很简单的,我的截图软 ...
- MYSQL进阶学习笔记十五:MySQL 的账号权限赋予!(视频序号:进阶_33,34)
知识点十六:MySQL的账号权限赋予(33) 一.MySQL权限简介 关于mysql的权限简单的理解就是mysql允许你做你全力以内的事情,不可以越界.比如只允许你执行select操作,那么你就不能执 ...
- 精选Java面试题
什么是隐式类型转换?什么是显示类型转换? 当将占位数少的类型赋值给占位数多的类型时,Java自动使用隐式类型转换(如int型转为long型).当把在级别高的变量的值赋给级别底变量时,必须使用显示类型转 ...
- !function(){}()和function(){}()区别
控制台打印结果如下所示,接下来看一下具体运行,参考https://swordair.com/function-and-exclamation-mark/: 让一个函数声明语句变成了一个表达式
- 准备看的ros相关源码
进程通信:lcm 导航:navigation 3D可视化工具:rviz Mobile Robot Programming Toolkit:mrpt 其他: 人体肌肉:simbody openslam ...
- Robot FrameWork基础学习(三)
一.关键字(Keyword)根据架构的区分可分为以下三层结构: 底层关键字.公共层关键字.特性关键字. 底层关键字一般与最底层的代码在关系,为上层公共关键字和特性关键字提供接口. 公共层关键字:一般是 ...
- Hadoop Shell 介绍
以 hadoop 2.7.3 为例 bin 目录下是最基础的集群管理脚本, 用户可通过该脚本完成各种功能, 如 HDFS 管理, MapReduce 作业管理等. 作为入门, 先介绍bin 目录下的 ...