如何重构“字符串类型”代码?
Posted
技术标签:
【中文标题】如何重构“字符串类型”代码?【英文标题】:How to refactor "stringly-typed" code? 【发布时间】:2013-02-10 11:41:09 【问题描述】:我目前正在开发一个代码库,其中有几类变量,例如数据库路径,它们简单地表示为字符串。这些(非)类型的大部分操作都在实用程序类中定义。
我创建了一个新类来表示一个数据库,操作定义为实例方法,采用传统的 OOP 风格。然而,通过大型代码库并对其进行重构以使用新类型是相当费力的。有人对如何快速有效地做到这一点有任何建议吗?
【问题讨论】:
既不将数据库路径存储在变量中,也不创建一个类来表示具有在方法中定义的操作的数据库,听起来不错。 【参考方案1】:对我来说,数据库路径听起来应该是字符串。还有什么意义?它们应该在配置文件或数据库中进行外部化。这是你的问题中最少的。
Persistence 已经出现了很多次(例如 Hibernate、Spring JDBC、iBatis 等),我想知道您如何改进它们。如果你不得不麻烦重构——而且你必须——我建议你使用 任何东西,而不是你所做的。
如果您必须写一些东西,请在 Google 上搜索“通用 DAO”。你会得到这样的东西:
http://www.ibm.com/developerworks/java/library/j-genericdao/index.html
如果您的作品没有按照类似的方式进行设计,请将其丢弃并重新考虑。
【讨论】:
直接使用 hibernate、spring 等的方法可能不是最好的,因此基于自己的代码的中间步骤可能是有正当理由的。我自己也见过几次。教hibernate和spring也是很费劲的。 我同意 Hibernate - 我不会向任何人推荐它。但我不能再不同意 Spring JDBC。它非常简单且设计精良。您可以使用 Spring 的部分内容,而无需掌握全部内容。【参考方案2】:迁移实用程序类以使用您的新类。那么实用程序类方法应该只包含两个语句。一个用于创建您的课程,另一个用于调用您的课程。之后,您可以内联实用程序类方法,从而消除对它的需要。
当你完成这些后,你需要寻找一种方法来不一遍又一遍地实例化你的新类。这应该通过将局部变量重构为在构造时初始化的实例字段来完成。
【讨论】:
【参考方案3】:我通常会尝试在应用程序/进程边界的限制处隔离字符串,例如当它们从数据库中检索或通过 Web 操作接收时。
在该应用程序/进程边界通常是将字符串映射/转换/反序列化为更合适的对象模型的理想位置,无论您使用什么语言都支持。
同样,对象模型可以在退出应用程序/进程边界时被映射/转换/序列化回字符串形式。
值得注意的是,这种字符串类型可能有些微妙。我经常看到 xml 侵入应用程序和域层。来自 .NET 领域的一个类似示例将无法在收到 ADO.NET 数据表(及其字符串列名和无类型字段值)后立即将它们映射到类/对象中。我毫不怀疑在 Java 世界中有许多类似的等价物。开玩笑说,Stringly Typing 不仅限于日期值。
【讨论】:
【参考方案4】:我在 C# 中使用的一种技术(并且刚刚移植到 Java - 如果我犯了错误,我很抱歉,我是 Java 新手)是创建 StringlyTyped 类,例如一个基类
public abstract class StringlyTyped
private String value;
public StringlyTyped (String value)
if (value == null)
throw new IllegalArgumentException("value must not be null");
this.value = value;
public String getValue() return value;
@Override
public boolean equals(Object other)
if (other == this)
return true;
if (other == null || !this.getClass().equals(other.getClass()))
return false;
StringlyTyped o = (StringlyTyped)other;
return o.getValue().equals(this.getValue());
@Override
public int hashCode() return this.getValue().hashCode();
@Override
public String toString() return this.getValue();
然后派生类
public class ProviderName extends StringlyTyped
public ProviderName(String value)
super(value);
及用法
public void Foo(ProviderName provider)
当您的方法具有许多 String 参数时,这是有意义的,例如你可以避免
public void Foo(String username, String password, String db, String table, String constraint)
而是使用像这样的强类型代码:
public void Foo(UserName username, Password password, DatabasePath db, TableName table...)
等等……
【讨论】:
以上是关于如何重构“字符串类型”代码?的主要内容,如果未能解决你的问题,请参考以下文章