程序员如何实践代码重用

时间:2008-10-26 08:28:30

标签: code-reuse

我是一个糟糕的程序员,因为我正在复制和粘贴。一个例子是,每当我连接到数据库并检索记录集时,我将复制先前的代码并进行编辑,复制设置datagridview和编辑的代码。我知道短语代码重用,但我实际上并没有使用它。我如何利用代码重用,以便我不必复制和粘贴数据库代码和datagridview代码。,

14 个答案:

答案 0 :(得分:9)

代码重用的本质是进行常规操作并对其进行参数化,以便它可以接受各种输入。

以简陋的printf为例。想象一下,如果你没有printf,只有write或类似的东西:

//convert theInt to a string and write it out.
char c[24];
itoa(theInt, c, 10);
puts(c);

现在这很糟糕,每次都要写,而且实际上是一种马车。因此,一些聪明的程序员决定他厌倦了这一点,并写了一个更好的功能,一举打印到stdout。

printf("%d", theInt);

使用它的可变参数和格式字符串,你不需要像printf那样花哨。即使只是一个简单的例程,例如:

void print_int(int theInt)
{
    char c[24];
    itoa(theInt, c, 10);
    puts(c);
}

会很快地做到这一点。这样,如果您想要将print_int更改为始终打印到stderr,您可以将其更新为:

void print_int(int theInt)
{
    fprintf(stderr, "%d", theInt);
}

现在你的所有整数都会被神奇地打印成标准错误。

您甚至可以将该功能和您编写的其他功能捆绑到一个库中,这只是您可以加载到程序中的代码集合。

遵循代码重用的做法就是为什么你甚至要连接一个数据库:有人创建了一些代码来将记录存储在磁盘上,重新设计它直到其他人可以使用,并决定将其称为数据库。

图书馆不会神奇地出现。它们由程序员创建,以使他们的生活更轻松,并使他们能够更快地工作。

答案 1 :(得分:4)

将代码放入例程中,并在需要执行代码时调用例程。

答案 2 :(得分:4)

查看Martin Fowler在book上的refactoring,或者一些与重构有关的互联网资源(也在stackoverflow上),以了解如何改进有重复气味的代码。

答案 3 :(得分:2)

首先,创建一个具有可重用功能的库。它们可以与不同的应用程序链接。它节省了大量时间并鼓励重复使用。

还要确保库已经过单元测试和记录。所以很容易找到合适的类/函数/变量/常量。

答案 4 :(得分:2)

良好的经验法则是,如果你使用相同的部分三次,并且显然可以概括它,而不是使它成为一个过程/函数/库。

但是,随着我年龄的增长,以及作为专业开发人员的经验,我更倾向于将代码重用视为最好的主意,原因有两个:

  1. 很难预测未来的需求,因此定义API非常困难,以便下次真正使用它们。这可能会花费你两倍的时间 - 一旦你把它变得更加通用,那么你第二次要重写它。在我看来,特别是最近的Java项目很容易出现这种情况,它们似乎总是在框架中重写,只是为了更容易“整合”或将来的任何东西。

  2. 在较大的组织中(我是其中一员),如果您必须依赖某些外部团队(内部或第三方),您可能会遇到问题。那么你的未来取决于他们的资金和资源。因此,使用外国代码或库可能是一个很大的负担。以类似的方式,如果你将一段代码分享给其他团队,那么他们可以期望你会维护它。

  3. 但请注意,这些更像是商业原因,因此在开源中,重复使用几乎总是一件好事。

答案 5 :(得分:2)

要获得代码重用,您需要成为...的主人。

  1. 给出能够捕捉其本质的名字。这真的很重要
  2. 确保它只做一件事。这真的回到了第一点,如果你不能用它的本质命名它,那么它往往做得太多了。
  3. 将事物放在某处合乎逻辑。这又回到了能够很好地命名并捕捉其本质......
  4. 将其与基于核心概念的事物进行分组。与上述相同,但表示不同: - )

答案 6 :(得分:1)

我认为解决问题的最佳方法是为您的重要函数创建一个单独的程序集。这样您就可以创建扩展方法或修改帮助程序自己组装..想想这个函数..

ExportToExcel(列出日期,字符串文件名)

这个方法可以用于你未来的excel导出函数,所以为什么不把它存储在你自己的帮助程序集中呢?这样你就可以添加对这些程序集的引用。

答案 7 :(得分:1)

首先要注意的是,通过使用复制和粘贴,您将重用代码 - 尽管不是以最有效的方式。 您已经认识到以前提出过解决方案的情况。

在考虑代码重用时,您需要注意两个主要范围。首先,项目中的代码重用,其次,项目之间的代码重用。

您有一段可以在项目中复制和粘贴的代码这一事实应该是一个提示,您正在查看的那段代码在其他地方很有用。现在是时候将它变成一个函数,并使它在项目中可用。 理想情况下,您应该用新函数替换该代码的所有出现,以便它(a)减少冗余代码,并(b)确保该代码块中的任何错误只需要在一个函数中修复而不是多个。

第二个范围,跨项目的代码重用,需要更多的组织才能获得最大的收益。这个问题已在其他几个SO问题中得到解决,例如。 herehere

一个良好的开端是将可能跨项目重用的代码组织成尽可能自包含的源文件。最大限度地减少所需的支持,项目特定代码的数量,因为这样可以更轻松地在新项目中重用整个文件。这意味着最大限度地减少项目特定数据类型的使用,最大限度地减少使用项目特定的全局变量等。

这可能意味着创建包含您知道在您的环境中有用的功能的实用程序文件。例如。如果您经常开发依赖于数据库的项目,则使用通用数据库函数。

答案 8 :(得分:0)

对于您给出的示例,适当的解决方案是编写一个函数,无论您何时粘贴块,都将其作为参数作为参数,然后使用适当的数据作为参数调用该函数。

答案 9 :(得分:0)

这在某种程度上取决于您正在使用的编程语言。在大多数语言中,您可以

  1. 编写一个函数,将其参数化以允许变化
  2. 编写一个函数对象,其成员可以保存不同的数据
  3. 开发一个(函数对象?)类的层次结构,实现更复杂的变体
  4. 在C ++中,您还可以开发模板以在编译时生成各种函数或类

答案 10 :(得分:0)

尝试并养成使用其他人的功能和库的习惯。

您通常会发现您的特定问题具有经过良好测试的优雅解决方案。

即使您找到的解决方案并不完美,您也可以通过了解其他人如何解决问题来获得对此问题的深入了解。

答案 11 :(得分:0)

我会在两个级别上这样做。首先在类或命名空间中,将在该范围内重用的代码片段放在一个单独的方法中,并确保它被调用。

第二种类似于您描述的情况。这是一个很好的候选者,可以放在库或帮助器/实用程序类中,可以更广泛地重用。

使用透视评估您正在做的所有事情是否可供其他人使用以进行重用是非常重要的。这应该是我们大多数人都没有意识到的编程的基本方法。

请注意,需要更详细地记录要重复使用的任何内容。它的命名约定是不同的,所有参数,返回结果和所需的任何约束/限制/先决条件都应该清楚地记录(在代码或帮助文件中)。

答案 12 :(得分:0)

简单:每当你发现自己的复制粘贴代码时,立即将 (即,在已经多次CP代码后不要这样做)转换为新功能。

答案 13 :(得分:0)

根据项目的大小可以改变答案。

对于较小的项目,我建议设置一个DatabaseHelper类来执行所有数据库访问。它只是打开/关闭连接和执行DB代码的包装器。然后在更高级别,您可以编写将要执行的DBCommands。

类似的技术可以用于更大的项目,但需要一些额外的工作,需要添加接口,DI,以及抽象出你需要了解的数据库。

您也可以尝试查看ORM,DAAB或以上Patterns and Practices Group

至于如何预防ole C& P? - 当你编写代码时,你需要定期检查它,如果你有相似的代码块,只能通过一个或两个参数变化,那么它总是很适合重构自己的方法。

现在我的伪代码示例:

Function GetCustomer(ID) as Customer
   Dim CMD as New DBCmd("SQL or Stored Proc")
   CMD.Paramaters.Add("CustID",DBType,Length).Value = ID
   Dim DHelper as New DatabaseHelper
   DR = DHelper.GetReader(CMD)
   Dim RtnCust as New Customer(Dx)
   Return RtnCust
End Function

Class DataHelper
  Public Function GetDataTable(cmd) as DataTable
    Write the DB access code stuff here.
    GetConnectionString
    OpenConnection
    Do DB Operation
    Close Connection
  End Function
  Public Function GetDataReader(cmd) as DataReader
  Public Function GetDataSet(cmd) as DataSet
  ... And So on ...
End Class