重构36计(1-6)

重构,其实很简单,它的目的就是让程序变得更容易被理解,更具有可维护性,结构更合理。重构应该是我们平时写代码过程中必不可少的一部分,比如给函数起了一个更好的名字、把大函数拆分成几个小函数等都属于重构。重构的经典书籍包括Martin Flower的《重构-改善既有代码的设计》、Joshua Kerievsky的《重构与模式》,本系列的所谓36计是我多年来使用最为频繁的重构策略和编码准则,有自己总结的,也有书上提到过的,希望对大家能有所帮助。
[b] 第一计:参数列表对象化[/b]
公有函数的参数应尽可能保持不变,因为很多地方都会调用它,修改参数后需要修改它的调用处,另外,它的参数列表不宜过长,数量尽量保持在5个以内,长参数列表会增加该函数的调用难度。对于参数较多或者参数经常变化的公有函数,较好的办法是引入参数对象,即该函数的参数只有一个,它就是参数对象,具体的参数都在该对象中声明,为函数引入参数对象有以下几个好处:
1、保持函数接口的不变性,修改函数参数只需修改参数对象中的成员变量。
2、调用方便,调用方不用再关心参数的顺序。
以下代码片段是一个添加用户函数的声明:[/size]
public long insertUser(String name,int age,String email,String address,String phone,String birthDay)

[size=medium]每当添加或删除用户的字段后都要修改insertUser的参数列表,调用者也需要修改,而且参数较多时,不容易记忆。
以下是引入参数对象后的形式:
public class UserParam{
public String name;
public int age;
public String email;
public String address;
public String phone;
public String birthDay;
}

public long insertUser(UserParam user);


[b]第二计:条件运算符赋值代替if else赋值[/b]
对于根据条件为变量赋值的情况,可以有两种方式,一种是通过if-else:
int value;
if(condition)
value = 1;
else
value = 2;

另一种是通过条件运算符:
int value = condition ? 1 : 2;

第二种方式明显要比第一种方式好,但是很多人却钟爱第一种方式,可能是if-else习惯了。

[b]第三计:节约使用系统资源[/b]
即使在写代码时,我们也应该养成“节俭”的习惯,不要随便浪费系统提供的资源,对于那些较占用空间、影响性能的对象,应该直到真正要用的时候才创建或者初始化,因此在提供这些对象的函数实现中,尽量采用如下形式:
// 管理数据库连接的类
public class DataBaseConnectionHolder{
private Connection conn;

public Connection getConnection(){
if(conn == null){
conn = new Connection();
conn.init();
}
return conn;
}
}

另外,我们可以通过引入缓存机制(如对象池)来充分利用系统资源

[b]第四计:为接口引入抽象版本[/b]
在声明一个新的接口时,不能保证该接口不会被修改,有可能会经常修改它,每一次修改接口都要修改相应的实现类,如果某个接口是公共库的一部分,那么修改接口的代价是较大的,用到该接口的所有程序都需要重新修改、编译...,通过为接口引入抽象版本可以解决这个问题,例如为下面的接口增加一个抽象类:
public interface Widget{
public void draw();
public void layout();
public void invalidate();
public void show();
}

public abstract class AbstractWidget implements Widget{
public abstract void draw();
public void layout(){};
public void invalidate(){};
public void show(){};
}

这样Widget的实现类可以直接从AbstractWidget继承,如果要修改Widget接口,则只需要修改AbstractWidget即可,对于其他实现类没有影响。

[b]第五计:消灭魔法数[/b]
编程新手一般都会直接将表示类型或状态的数字直接写在处理逻辑中,代码的作者能明白该数字所表示的含义,但其他人读到这段代码时就很有可能看不懂了。即使代码的作者再过一段时间来看这部分代码,也可能会忘记该数字的含义,而且,当我们要修改魔法数的值时,过程是很繁琐的,很有可能会有所遗漏,所以,最好的办法是彻底消灭程序中的所有魔法数,通过常量定义、枚举等方式来避免魔法数的出现。

[b]第六计:使用断言、异常确保实现的正确性[/b]
使用断言的目的是告知其他程序员代码中某处必须要遵守的规矩,它是debug版本中的一种确保程序实现正确性的手段,在正式发布的版本中,断言是不起作用的。在java中,启用断言需要增加一个编译选项,不过可以通过抛出异常来达到相同目的,使用异常比断言要危险,因为在程序的正式发布版本中会引起崩溃,不过有时候崩溃总比程序的诡异行为更好,例如:
// 表示集合的类
public class Collection{
// 添加元素到集合中
public void addElement(Element e){};

// 获取指定位置的元素
public void getElement(int index){};
}

// 表示只读集合的类
public class ReadOnlyCollection extends Collection{
// 添加元素到集合中
public void addElement(Element e){
throw new UnsupportedOperationException("只读集合,不允许添加元素");
}

// 获取指定位置的元素
public void getElement(int index){};
}

调用ReadOnlyColletion派生类必须遵守规矩:不能调用addElement,否则抛出异常干掉程序!

ref:http://blog.csdn.net/m13666368773/article/details/7472201
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值