13

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

4

14 回答 14

9

代码重用的本质是对一个通用的操作进行参数化,使其能够接受各种输入。

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

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

现在这很糟糕,每次都必须写,实际上有点麻烦。所以一些聪明的程序员决定他厌倦了这个并写了一个更好的函数,一举将东西打印到标准输出。

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);
}

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

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

遵循代码重用的做法是您甚至可以连接数据库的原因:有人创建了一些代码来将记录存储在磁盘上,然后对其进行了重新设计,直到其他人可以使用它,然后决定将其称为数据库。

图书馆不会神奇地出现。它们是由程序员创建的,目的是让他们的生活更轻松,让他们更快地工作。

于 2008-10-26T09:11:18.403 回答
4

将代码放入例程中,并在您希望执行该代码时调用该例程。

于 2008-10-26T08:31:22.993 回答
4

查看 Martin Fowler 的关于重构的,或众多与重构相关的 Internet 资源(也在 stackoverflow 上),了解如何改进有重复气味的代码。

于 2008-10-26T08:56:19.040 回答
2

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

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

于 2008-10-26T08:31:42.367 回答
2

好的经验法则是,如果您使用相同的部分 3 次,显然可以将其概括,而不是使其成为过程/函数/库。

然而,随着我年龄的增长,以及作为一名专业开发人员的经验越来越丰富,我更倾向于认为代码重用并不总是最好的想法,原因有两个:

  1. 很难预测未来的需求,因此很难定义 API,以便您下次真正使用它们。它可能会花费你两倍的时间——一旦你让它更通用,那么第二次你无论如何都要重写它。在我看来,尤其是最近的 Java 项目很容易出现这种情况,它们似乎总是在框架中被重写,只是为了更“更容易集成”或将来的任何东西。

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

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

于 2008-10-26T13:57:18.530 回答
2

要获得代码重用,您需要成为...的大师

  1. 给事物起名字来抓住它们的本质。这真的很重要
  2. 确保它只做一件事。这真的回到了第一点,如果你不能从本质上去命名它,那么它往往做得太多了。
  3. 将事物定位在合乎逻辑的地方。这又回到了能够很好地命名事物并捕捉其本质......
  4. 将其与基于中心概念的事物组合在一起。与上述相同,但说法不同:-)
于 2008-10-27T08:41:12.037 回答
1

我认为回答你的问题的最好方法是为你的重要功能创建一个单独的程序集。这样你可以创建扩展方法或修改帮助程序本身。想想这个函数。

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

此方法可用于您未来的 excel 导出功能,所以为什么不将其存储在您自己的辅助程序集中。我这样您只需添加对这些程序集的引用。

于 2008-10-26T12:23:46.970 回答
1

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

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

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

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

一个好的开始是将可能跨项目重用的代码组织到尽可能独立的源文件中。最大限度地减少所需的支持、项目特定的代码,因为这将使在新项目中重用整个文件变得更加容易。这意味着最小化项目特定数据类型的使用,最小化项目特定全局变量的使用等。

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

于 2011-09-16T05:13:55.620 回答
0

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

于 2008-10-26T08:33:07.420 回答
0

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

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

尝试养成使用其他人的函数和库的习惯。

您通常会发现您的特定问题有一个经过充分测试的优雅解决方案。

即使您找到的解决方案并不完美,您也可能会通过查看其他人如何解决问题来深入了解该问题。

于 2008-10-26T08:53:57.313 回答
0

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

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

重要的是要评估您正在做的每件事,是否可以将其提供给其他人以供重用。这应该是我们大多数人都没有意识到的编程的基本方法。

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

于 2008-10-26T09:27:04.720 回答
0

简单:每当您发现自己在复制粘贴代码时,立即将其取出(即,不要在您已经 CP 多次编写代码之后再这样做)到一个新函数中。

于 2008-10-26T12:29:35.850 回答
0

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

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

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

您也可以尝试查看 ORM、DAAB 或模式和实践组

至于如何预防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
于 2008-10-26T12:39:20.510 回答