【问题标题】:How can I avoid code duplication with many small classes?如何避免许多小类的代码重复?
【发布时间】:2009-03-17 17:47:03
【问题描述】:

我有不同的类,称为EnglishSpanishFrench 等:

Class English{
    String name = "English";
    String alias = "ENG";
}

Class French{
    String name = "French";
    String alias = "Fre";
}

类似的其他语言课程。

还有一个叫Language的类:

Class Language{
    String name = "";
    String alias = "";
}

根据我的要求,我想将英语/法语/西班牙语转换为我的语言课程。

Class ABC{

    main(){
        Language lan = new Language();
        Object obj = getObject(1);
        if(obj instanceof English){
            lan.name = ((English)obj).name;
            lan.aliasName = ((English)obj).aliasName;
        }
    }

}

如果我有 10 种语言,我是否需要为 10 种不同的语言编写相同的代码? 在这种情况下,如何创建一个方法并将这些参数作为参数传递? 像这样的:

setVariablesForLanguage(String className, Object obj)

这里我只展示了 2 个变量,但我的类将包含 100 多个变量.. 我的实际要求是我想从其中一种语言设置我的语言变量..

【问题讨论】:

    标签: java oop casting


    【解决方案1】:

    如果您要创建几个小类,每个类都持有常量值,那么您不应该让它们成为类。我建议让它们成为 Language 的常量实例:

    public static final Language ENGLISH = new Language("English", "Eng");
    public static final Language FRENCH  = new Language("French",  "Fre");
    

    并给 Language 一个构造函数来匹配。 (实际上,这看起来更像是enum,但我不会一次过多地向你倾诉。)

    然后在你的主代码中,不要检查它是否是英语、法语等的实例。只需检查它是否是一种语言,然后调用

    Language lan = new Language();
    Object obj = getObject(1);
    if(obj instanceof Language){
        lan.name = ((Language)obj).name;
        lan.aliasName = ((Language)obj).aliasName;
    }
    

    【讨论】:

    • +1,正是我想要发布的内容(也许除了 isinstance-stuff,因为我不喜欢这样;))
    • 这里的原则是“改变行为的子类,而不是数据”。由于行为没有改变,因此您不需要多个类。
    • 实际上您可能需要枚举,但功能与此答案建议的功能几乎相同。
    【解决方案2】:

    使用声明 Name 和 Alias 属性的接口或抽象类。为每个类实现接口或从抽象类派生。

    这是适用于“许多看起来非常相似的类”的常见问题的一般原则 - 但这里到底发生了什么?为什么会有多个英语实例?这里的真实状态是什么?

    真的想要smart enum吗?

    【讨论】:

      【解决方案3】:

      如果我有 10 种语言,我是否需要为 10 种不同的语言编写相同的代码?

      不,实际上你可能根本不需要这些课程。

      如果它们具有相同的属性并且唯一使它们不同的是这些属性的值,那么您可以有一个类 ( Language ) 并为每种语言使用不同的值。

      顺便说一句,所以当您说 alais 时,您的意思是别名?

      你可以这样:

      public class Language  {
      
          String name;
          String alias;
      
          public Language( String aName, String anAlias ) { 
              this.name = aName;
              this.alias = anAlias;
          }
      }
      

      并相应地设置值。

      如果您更改“getObject()”的签名,那么它会返回对象,而是返回语言本身,那么您可以从此更改您的代码:

      Language lan = new Language();
      
      Object obj = getObject(1);
      
      if(obj instanceof English){
      
          lan.name = ((English)obj).name;
      
          lan.aliasName = ((English)obj).alias;
      }
      

      到这里:

      Language lang  = getObject(1);
      

      就是这样。在getObject 中,你可以这样定义它:

      public Language getObject( int id ) { 
           switch( id ) { 
                case 0:  return new Language("English", "ENG");
                case 1:  return new Language("French", "FRE");
                case 2:  return new Language("Spanish", "ESP");
                case 3:  return new Language("German", "GER");
                case 4:  return new Language("Portuguese", "POR");
                ....
                etc. 
            }
      }
      

      您可能意识到,当行为不同时,创建一个子类或不同类是有意义的。当行为相同时,改变的只有数据,那么参数化类就足够了。

      最后一句话:

      根据您的需要,您可能会查看Locale 类并可能阅读此article 以了解Java 对这种情况有什么作用。我不知道您的代码是否需要它,但它可能会有所帮助。

      【讨论】:

      • 你为什么不只返回一次 new Language( ((Language)obj).name , ((Language)obj).alias) 。编写这样的 switch case 块并复制代码“n”次怎么办?
      • @Livepool:我什至不知道 getObject 方法里面是什么,很可能对象是在里面创建的。为什么我要创建 Object 而我们可以创建非常 Language 实例。只有“Chinni”可以分辨。
      【解决方案4】:

      这不是您问题的完整解决方案(它甚至可能不是您真正的解决方案),但我想指出一些我认为您提供的代码会更好的事情。

      对于提供的代码,您最好编写如下代码:

      abstract class Language
      {
          private final String name;
          private final String alias;
      
          public Language(final String m, final String a)
          {
              name  = n;
              alias = a;
          }
      
          public String getName()
          {
              return (name);
          }
      
          public String getAlias()
          {
              return (alias);
          }
      }
      
      class English
          extends Language
      {
          public English()
          {
              super("English", "ENG");
          }
      }
      
      class ABC
      {
          public static void main(final String[] argv)
          {
              fnal Language lang;
      
              lang = getObject(1);
          }
      }
      

      一般:

      • 您应该尽可能避免使用 instanceof。
      • 当你有相同类型的东西时(如英语、法语等......你应该创建一个父类并将常见的东西放入其中)。

      【讨论】:

      • - 当唯一改变的是数据时,只需参数化,不要子类化。
      【解决方案5】:

      为什么不让英语、法语等都成为语言的子类?

      那么你的代码会更简单:

      
      Class ABC{
      
      main(){
      
       Language lan = getObject(1);
      
      }
      
      }
      

      编辑:如上所述,语言作为接口或抽象类也可能做得更好。

      【讨论】:

      • 如上所述,“语言”概念的行为映射到一个类。每种语言都是此类的一个实例。为每种语言定义一个子类不会(根本)有助于避免代码重复!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-29
      • 1970-01-01
      • 1970-01-01
      • 2011-11-18
      • 1970-01-01
      相关资源
      最近更新 更多