如何重构“字符串类型”代码?

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...) 

等等……

【讨论】:

以上是关于如何重构“字符串类型”代码?的主要内容,如果未能解决你的问题,请参考以下文章

如何分配“字符串”类型的值?输入“UIImage?”

VC++ TCHAR类型字符串操作

在 Typescript 中,如何声明一个返回字符串类型数组的函数?

Python 字符串类型列表转换成真正列表类型

错误:类型不匹配:推断类型是字符串?但布尔值是预期的

如何将phpinfo字符串类型转换