重构学习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 ...
随机推荐
- Node中的Socket.IO 简单Demo及说明
注:下面Demo的Server和Client都是纯后端. 并没有web页面. Server端代码: var express = require('express'); var app = expres ...
- Mac查看端口
lsof -i tcp:port eg: lsof -i tcp:8899
- vue指令与$nextTick 操作DOM的不同之处
异步更新队列 可能你还没有注意到,Vue 异步执行 DOM 更新.只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变.如果同一个 watcher 被多次触发,只会被推 ...
- codeforces 715c
题目大意:给定一个有N个点的树,问其中有多少条路径满足他们的边权连成的数对M取余为0.其中gcd(M,10)=1. 题解: 很亲民的点分治题目,对每一层点分治,预处理每个点到当前根的数字并对m取余,和 ...
- linux下mysql开启二进制日志
mysql的查询日志,慢查询日志,错误日志,网上的设置方法是正确的.但在二进制日志上设置有问题.正确的设置方法如下, 在/etc/my.cnf文件中[mysqld]下加上: server-id = 1 ...
- ios 使用json
1.从https://github.com/stig/json-framework/中下载json框架:json-framework 2.解压下载的包,将class文件夹下的所有文件导入到当前工程下. ...
- spring 从jsp到jsp
小例子 1.jar信息 2.web.xml文件配置 <?xml version="1.0" encoding="UTF-8"?> <web-a ...
- ubuntu中使用gensim+word2vec[备忘]
python版本: 2.7.12 0. 安装python和pip 1. 用pip依次安装: numpy, cython,scipy,pattern,word2vec 五个工具包 2. 用pip安装ge ...
- CentOS6.3安装 Oracle 11g R2
1.设置系统1.1.包需求 11g很人性化了,增加了检查的机制,还有就是不象10g那样在64位下要安装很多的32位包,只需要安装一个gcc-32bit-4.3就OK了.下列表必须要安装:binutil ...
- Django (2006, 'MySQL server has gone away') 本地重现与解决
最近我们的Django项目供Java Sofa应用进行tr调用时, 经常会出现一个异常: django.db.utils.OperationalError: (2006, 'MySQL server ...