重构学习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 ...
随机推荐
- platform_set_drvdata()/platform_get_drvdata()/container_of()【转】
本文转载自:http://blog.csdn.net/angle_birds/article/details/8443695 platform_set_drvdata(struct platform_ ...
- requirejs测试
参考资料:http://www.ruanyifeng.com/blog/2012/11/require_js.html 一.文件目录 二.html <!DOCTYPE html> < ...
- jsp报An error has occurred. See error log for more details. Argument not valid错误
An error has occurred. See error log for more details. Argument not valid 翻译过来是:一个错误已经发生.看到更多的细节错误日志 ...
- python学习笔记:第二天(运算符)
Python3 运算符 注:以下部分示例源自于http://www.runoob.com/ 1.算术运算符 假设变量a为10,变量b为20: 运算符 描述 实例 + 加 - 两个对象相加 a + b ...
- git比较两个版本,获取所有代码有差别的文件,并拷贝到一个文件夹中
git diff 3b3855d a024af5 --name-only | xargs -i cp '{}' ./update/ --parents 解释:通过xargs 命令,把git diff ...
- userData IE
蛮讨厌IE的,因为他常常需要特别照顾,就像DOM Storage(sessionStorage和localStorage)只能支持IE8+,对于以下的只能使用userData. 原理:通过在docum ...
- JavaScript实现按键记录,并在关掉网页之前把记录的内容post出去
最近陈老师让我给新架构加一个按键记录的业务.去学习了JavaScript,网上找了一些代码,最后写出来了: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTM ...
- TModJS:使用tmodjs
ylbtech-TModJS:使用tmodjs 1.返回顶部 1. 1.安装 npm install -g tmodjs 2.配置 我的模板都放在tpl文件夹中,htmls用于存放模板页面,每一个后缀 ...
- 《Kubernetes权威指南第2版》学习(二)一个简单的例子
1: 安装VirtualBox, 并下载CentOS-7-x86_64-DVD-1708.iso, 安装centOS7,具体过程可以百度. 2:开启centOS的SSH, 步骤如下: (1) yum ...
- Robot FrameWork基础学习(三)
一.关键字(Keyword)根据架构的区分可分为以下三层结构: 底层关键字.公共层关键字.特性关键字. 底层关键字一般与最底层的代码在关系,为上层公共关键字和特性关键字提供接口. 公共层关键字:一般是 ...