5
回答
【讨论】代码复用的利与弊

谈谈我对复用的理解

一说起代码复用,仿佛是一个令人振奋的褒义词,高复用的代码带来的是低耦合,易维护,皮拉扒拉的...

但是有些复用是否会对代码的执行效率造成影响呢,全是正面的没有负面的吗?

1.高复用的一个原则是,尽可能把一个包含很多代码(50行以上)的方法进行分割,虽然方法是分割出来的,但是不能保证每个分割出来的方法都至少被复用一次以上,因此编译器得不断的切换方法来完成本来在一个方法中就可以完成代码。如:

方式1:

// 未复用
	public void noRepeatUse() {
		int num1 = 0;
		num1 = 1 + 1;
		int num2 = 0;
		num2 = 2 + 2;
		int count = num1 + num2;
		System.out.println(count);
	}
方式2:
// 复用,不保证t1(),t2()以后都能够用到
	public void repeatUse() {
		int num1 = t1();
		int num2 = t2();
		int count = num1 + num2;
		System.out.println(count);
	}

	public int part1() {
		return 1 + 1;
	}

	public int part2() {
		return 2 + 2;
	}
这样要完成输出一个count,方式1只要执行6行,方法2要执行4行+2个方法,编译器在查询并执行t1这个方法的开销难道不比执行执行 num = 1+1这样一行要大么?


此外,复用有可能还会带来不必要的开销与判断,比如:

最初只设计了下面一个方法,该方法被多处复用,对某个对象的list进行输出:


public void originRepeatUse(List<Integer> list){
		ShardedJedis jedis = verifyPool.getResource();
		try {
			for(Integer i : list){
				System.out.println(i);
				System.out.println(i + 11);
				System.out.println(i + 22);
				System.out.println(i + 33);
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			verifyPool.returnResource(jedis);
		}
		
	}
现增加一个需求,只对单个对象进行输出


方法一,直接添加一个仅对对象输出方法

public void noRepeat(Integer i){
		ShardedJedis jedis = verifyPool.getResource();
		try {
			System.out.println(i);
			System.out.println(i + 11);
			System.out.println(i + 22);
			System.out.println(i + 33);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			verifyPool.returnResource(jedis);
		}
	}
方法二,对重复的输出代码进行服用


public void repeatObj(Integer i){
		ShardedJedis jedis = verifyPool.getResource();
		try {
			this.repeat(i);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			verifyPool.returnResource(jedis);
		}
	}
	
	public void repeatList(List<Integer> list){
		ShardedJedis jedis = verifyPool.getResource();
		try {
			for(Integer i : list){
				this.t4(i);
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			verifyPool.returnResource(jedis);
		}
		
	}
	
	public void repeat(Integer i){
		System.out.println(i);
		System.out.println(i + 11);
		System.out.println(i + 22);
		System.out.println(i + 33);
	}
方法3,无论使用的是list还是obj,都当做list处理,调用repeatList这个方法:


public void main(){
		List<Integer> list = new ArrayList();
		list.add(1);
		this.repeatList(list);
	}
	
	public void repeatList(List<Integer> list){
		ShardedJedis jedis = verifyPool.getResource();
		try {
			for(Integer i : list){
				this.t4(i);
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			verifyPool.returnResource(jedis);
		}
		
	}
	
	public void t4(Integer i){
		System.out.println(i);
		System.out.println(i + 11);
		System.out.println(i + 22);
		System.out.println(i + 33);
	}

三种方法,看上去第三种的复用率最高,但是由此new 出来的list,这种额外的开销相比复用来说,是否值得呢?

相比之下你会如何选择呢?

想听听大家对复用这个东东的看法。



<无标签>
举报
kingdelee
发帖于4年前 5回/448阅
共有5个答案 最后回答: 4年前

哈。谈复用,不得不谈另外两个东西。一个是资源,一个是逻辑关联(也可以看功能)。

代码复用,这个比较笼统。你说外部dll,或者插件,甚至可多进程并发的整体程序算不算代码复用呢?

如果只是谈局部的,那么也存在不同的切割方式,oo肯定是根据类来,而过程化的,通常需要根据函数来。 oo的复用,和过程化的复用,名词相同,但实际有很大区别。oo方面我就不放屁了。实话实说,就我开发的层面,和oo没什么关系。

而就过程化方面,我们再简单点理解,资源只和存储有关,诸如io的情况我们放一边不谈。那么代码复用就存在从几个角度的分解。

包括,状态迁移角度,这和逻辑有关,位宽操作角度,存储空间维护等等。

抛开具体的复用方法先不谈,我们需要确认下代码复用的目的是什么?如你说的,易维护,降低重复开发。

那么如果仅就这两个目的,(效率性能放一边不谈),那么对于其他语言我也暂不讨论,仅就c语言,#define就是代码复用,而函数调用,则不算代码复用,因为函数已经将逻辑,存储资源,位宽 操作方式具体化了。

#define 谈不上易维护,如果你的#define写的需要改来改去,那么是设计水平问题。#define可以称属于免维护的代码复用。哈。

c语言让我最爽和最容易加快开发速度和执行速度的(包括代码复用),我认为有3点,

1、#define 

2、强制类型转换

3、灵活的指针操作(包括数据指针和goto longjmp之类的跳转操作)

引用来自“中山野鬼”的答案

哈。谈复用,不得不谈另外两个东西。一个是资源,一个是逻辑关联(也可以看功能)。

代码复用,这个比较笼统。你说外部dll,或者插件,甚至可多进程并发的整体程序算不算代码复用呢?

如果只是谈局部的,那么也存在不同的切割方式,oo肯定是根据类来,而过程化的,通常需要根据函数来。 oo的复用,和过程化的复用,名词相同,但实际有很大区别。oo方面我就不放屁了。实话实说,就我开发的层面,和oo没什么关系。

而就过程化方面,我们再简单点理解,资源只和存储有关,诸如io的情况我们放一边不谈。那么代码复用就存在从几个角度的分解。

包括,状态迁移角度,这和逻辑有关,位宽操作角度,存储空间维护等等。

抛开具体的复用方法先不谈,我们需要确认下代码复用的目的是什么?如你说的,易维护,降低重复开发。

那么如果仅就这两个目的,(效率性能放一边不谈),那么对于其他语言我也暂不讨论,仅就c语言,#define就是代码复用,而函数调用,则不算代码复用,因为函数已经将逻辑,存储资源,位宽 操作方式具体化了。

#define 谈不上易维护,如果你的#define写的需要改来改去,那么是设计水平问题。#define可以称属于免维护的代码复用。哈。

c语言让我最爽和最容易加快开发速度和执行速度的(包括代码复用),我认为有3点,

1、#define 

2、强制类型转换

3、灵活的指针操作(包括数据指针和goto longjmp之类的跳转操作)

感谢野鬼童鞋深夜了还发表这么有见解的评论哈,可惜C我都忘了差不多了。你说性能放一边不谈,我刚刚举得那几个例子其实刚好想谈的就是因为复用带来的性能正负影响。
语言底层写好的代码,我们肯定是拿来复用的,不用自己再写,当然很方便,但是纵观很多第三方的简化方法,如apache的String.isEmpty(str)和自己手写判断 == null ,equals("")其实都一样,当然我会选择前者,性能管他呢,我可不希望我的代码出现一堆重复的判断这些java底层都不提供的该死的常用判断,可某些对性能要求苛刻的环境,这些是否复用是否需要注意呢,还是完全忽略不计?

引用来自“kingdelee”的答案

引用来自“中山野鬼”的答案

哈。谈复用,不得不谈另外两个东西。一个是资源,一个是逻辑关联(也可以看功能)。

代码复用,这个比较笼统。你说外部dll,或者插件,甚至可多进程并发的整体程序算不算代码复用呢?

如果只是谈局部的,那么也存在不同的切割方式,oo肯定是根据类来,而过程化的,通常需要根据函数来。 oo的复用,和过程化的复用,名词相同,但实际有很大区别。oo方面我就不放屁了。实话实说,就我开发的层面,和oo没什么关系。

而就过程化方面,我们再简单点理解,资源只和存储有关,诸如io的情况我们放一边不谈。那么代码复用就存在从几个角度的分解。

包括,状态迁移角度,这和逻辑有关,位宽操作角度,存储空间维护等等。

抛开具体的复用方法先不谈,我们需要确认下代码复用的目的是什么?如你说的,易维护,降低重复开发。

那么如果仅就这两个目的,(效率性能放一边不谈),那么对于其他语言我也暂不讨论,仅就c语言,#define就是代码复用,而函数调用,则不算代码复用,因为函数已经将逻辑,存储资源,位宽 操作方式具体化了。

#define 谈不上易维护,如果你的#define写的需要改来改去,那么是设计水平问题。#define可以称属于免维护的代码复用。哈。

c语言让我最爽和最容易加快开发速度和执行速度的(包括代码复用),我认为有3点,

1、#define 

2、强制类型转换

3、灵活的指针操作(包括数据指针和goto longjmp之类的跳转操作)

感谢野鬼童鞋深夜了还发表这么有见解的评论哈,可惜C我都忘了差不多了。你说性能放一边不谈,我刚刚举得那几个例子其实刚好想谈的就是因为复用带来的性能正负影响。
语言底层写好的代码,我们肯定是拿来复用的,不用自己再写,当然很方便,但是纵观很多第三方的简化方法,如apache的String.isEmpty(str)和自己手写判断 == null ,equals("")其实都一样,当然我会选择前者,性能管他呢,我可不希望我的代码出现一堆重复的判断这些java底层都不提供的该死的常用判断,可某些对性能要求苛刻的环境,这些是否复用是否需要注意呢,还是完全忽略不计?
如果是oo,拜托,不要考虑性能,我是说代码级的。而是从业务逻辑中,好好注意实现方法。同样的逻辑,分两个函数写,还是分一个函数写,一个函数里面多了一个if判断,还是少了一个if判断,这些事情,别说oo的代码,就是c的代码,在没有经过大量数据测试证明这里存在瓶劲时,都不用可以调整,而尽可能保证逻辑的清晰和简单化。一个被我自己无数次证实的经验,相同的一个逻辑,如果代码写的越简单,效率越高。至少越简单的代码,编译器越容易理解。哈。

引用来自“中山野鬼”的答案

引用来自“kingdelee”的答案

引用来自“中山野鬼”的答案

哈。谈复用,不得不谈另外两个东西。一个是资源,一个是逻辑关联(也可以看功能)。

代码复用,这个比较笼统。你说外部dll,或者插件,甚至可多进程并发的整体程序算不算代码复用呢?

如果只是谈局部的,那么也存在不同的切割方式,oo肯定是根据类来,而过程化的,通常需要根据函数来。 oo的复用,和过程化的复用,名词相同,但实际有很大区别。oo方面我就不放屁了。实话实说,就我开发的层面,和oo没什么关系。

而就过程化方面,我们再简单点理解,资源只和存储有关,诸如io的情况我们放一边不谈。那么代码复用就存在从几个角度的分解。

包括,状态迁移角度,这和逻辑有关,位宽操作角度,存储空间维护等等。

抛开具体的复用方法先不谈,我们需要确认下代码复用的目的是什么?如你说的,易维护,降低重复开发。

那么如果仅就这两个目的,(效率性能放一边不谈),那么对于其他语言我也暂不讨论,仅就c语言,#define就是代码复用,而函数调用,则不算代码复用,因为函数已经将逻辑,存储资源,位宽 操作方式具体化了。

#define 谈不上易维护,如果你的#define写的需要改来改去,那么是设计水平问题。#define可以称属于免维护的代码复用。哈。

c语言让我最爽和最容易加快开发速度和执行速度的(包括代码复用),我认为有3点,

1、#define 

2、强制类型转换

3、灵活的指针操作(包括数据指针和goto longjmp之类的跳转操作)

感谢野鬼童鞋深夜了还发表这么有见解的评论哈,可惜C我都忘了差不多了。你说性能放一边不谈,我刚刚举得那几个例子其实刚好想谈的就是因为复用带来的性能正负影响。
语言底层写好的代码,我们肯定是拿来复用的,不用自己再写,当然很方便,但是纵观很多第三方的简化方法,如apache的String.isEmpty(str)和自己手写判断 == null ,equals("")其实都一样,当然我会选择前者,性能管他呢,我可不希望我的代码出现一堆重复的判断这些java底层都不提供的该死的常用判断,可某些对性能要求苛刻的环境,这些是否复用是否需要注意呢,还是完全忽略不计?
如果是oo,拜托,不要考虑性能,我是说代码级的。而是从业务逻辑中,好好注意实现方法。同样的逻辑,分两个函数写,还是分一个函数写,一个函数里面多了一个if判断,还是少了一个if判断,这些事情,别说oo的代码,就是c的代码,在没有经过大量数据测试证明这里存在瓶劲时,都不用可以调整,而尽可能保证逻辑的清晰和简单化。一个被我自己无数次证实的经验,相同的一个逻辑,如果代码写的越简单,效率越高。至少越简单的代码,编译器越容易理解。哈。
好吧,我上面写的java,结论是OO不必太计较这种性能的东东,尽快能的让逻辑清晰,比代码复用的性能要重要

引用来自“kingdelee”的答案

引用来自“中山野鬼”的答案

引用来自“kingdelee”的答案

引用来自“中山野鬼”的答案

哈。谈复用,不得不谈另外两个东西。一个是资源,一个是逻辑关联(也可以看功能)。

代码复用,这个比较笼统。你说外部dll,或者插件,甚至可多进程并发的整体程序算不算代码复用呢?

如果只是谈局部的,那么也存在不同的切割方式,oo肯定是根据类来,而过程化的,通常需要根据函数来。 oo的复用,和过程化的复用,名词相同,但实际有很大区别。oo方面我就不放屁了。实话实说,就我开发的层面,和oo没什么关系。

而就过程化方面,我们再简单点理解,资源只和存储有关,诸如io的情况我们放一边不谈。那么代码复用就存在从几个角度的分解。

包括,状态迁移角度,这和逻辑有关,位宽操作角度,存储空间维护等等。

抛开具体的复用方法先不谈,我们需要确认下代码复用的目的是什么?如你说的,易维护,降低重复开发。

那么如果仅就这两个目的,(效率性能放一边不谈),那么对于其他语言我也暂不讨论,仅就c语言,#define就是代码复用,而函数调用,则不算代码复用,因为函数已经将逻辑,存储资源,位宽 操作方式具体化了。

#define 谈不上易维护,如果你的#define写的需要改来改去,那么是设计水平问题。#define可以称属于免维护的代码复用。哈。

c语言让我最爽和最容易加快开发速度和执行速度的(包括代码复用),我认为有3点,

1、#define 

2、强制类型转换

3、灵活的指针操作(包括数据指针和goto longjmp之类的跳转操作)

感谢野鬼童鞋深夜了还发表这么有见解的评论哈,可惜C我都忘了差不多了。你说性能放一边不谈,我刚刚举得那几个例子其实刚好想谈的就是因为复用带来的性能正负影响。
语言底层写好的代码,我们肯定是拿来复用的,不用自己再写,当然很方便,但是纵观很多第三方的简化方法,如apache的String.isEmpty(str)和自己手写判断 == null ,equals("")其实都一样,当然我会选择前者,性能管他呢,我可不希望我的代码出现一堆重复的判断这些java底层都不提供的该死的常用判断,可某些对性能要求苛刻的环境,这些是否复用是否需要注意呢,还是完全忽略不计?
如果是oo,拜托,不要考虑性能,我是说代码级的。而是从业务逻辑中,好好注意实现方法。同样的逻辑,分两个函数写,还是分一个函数写,一个函数里面多了一个if判断,还是少了一个if判断,这些事情,别说oo的代码,就是c的代码,在没有经过大量数据测试证明这里存在瓶劲时,都不用可以调整,而尽可能保证逻辑的清晰和简单化。一个被我自己无数次证实的经验,相同的一个逻辑,如果代码写的越简单,效率越高。至少越简单的代码,编译器越容易理解。哈。
好吧,我上面写的java,结论是OO不必太计较这种性能的东东,尽快能的让逻辑清晰,比代码复用的性能要重要

用java 在代码级别追求性能,真的叫做没事找事。 当然业务逻辑的化简,实现流程的化简,这肯定是需要的。java要说唯一的优势,就是一个比较纯粹的oo,对于很多业务逻辑可以更好的开发,包括架构,框架等,这是相对C++而言。至于跨平台和可实现强大的各种底层功能,这种话也就听听得了,别太当真。

要说跨平台的能力,java在c/c++面前只能称跨桌面。几乎所有的cpu的厂家都提供c/c++的编译器和基础库,而只有有限的硬件平台才支持jre。

所以我始终强调,各忙各的事。。。java就安心做好业务。底层的东西,不要考虑太多。这本身就是java语言出现的初衷。快速的无需考虑运行环境特性的应用软件开发的工具。而不是开发快速的执行代码。

--- 共有 1 条评论 ---
乌龟壳c有内联函数优化,java也有,多几个函数应该也不会有事。java主要是好多东西要做得很灵活,框架之类的增加了负担,倒不如在需要灵活性的地方换语言。 4年前 回复
顶部