【问题标题】:How to refactor "stringly-typed" code?如何重构“字符串类型”代码?
【发布时间】:2023-03-07 23:52:01
【问题描述】:

我目前正在开发一个代码库,其中有几类变量,例如数据库路径,它们简单地表示为字符串。这些(非)类型的大部分操作都在实用程序类中定义。

我创建了一个新类来表示一个数据库,操作定义为实例方法,采用传统的 OOP 风格。然而,通过大型代码库并对其进行重构以使用新类型是相当费力的。有人对如何快速有效地做到这一点有任何建议吗?

【问题讨论】:

  • 既不将数据库路径存储在变量中,也不创建一个类来表示具有在方法中定义的操作的数据库,听起来不错。

标签: java string oop types refactoring


【解决方案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...) 
      

      等等……

      【讨论】:

        猜你喜欢
        • 2017-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-07
        • 2012-07-11
        • 1970-01-01
        • 2012-08-24
        相关资源
        最近更新 更多