【问题标题】:Is it possible to create a generic method that is suitable for different classes in Java?是否可以创建适用于 Java 中不同类的泛型方法?
【发布时间】:2018-03-27 18:03:26
【问题描述】:

我有不同的类,它们的结构如下:

public class MyClass {
    private String name;
    private List<International> internationalList;
}

我想要的是有一个给定本地化的通用方法(例如:“en-us”),它在国际列表中搜索并使用正确的语言设置名称。

例子:

 public MyClass myMethod(String local, MyClass object){

            for (International international : object.internationalList){
                if(local.equals(international.language)){
               object.name = international.translation
         }
      }
    return myObject;
 }

我不想为每个班级都重新编写这段代码。是否可以创建一个适用于所有具有这种结构的类的泛型方法?

【问题讨论】:

  • 不行,除非你可以在这些类之间建立一个共同的契约
  • 你能让所有这些类实现一个通用接口吗?
  • 你想过使用接口还是抽象类?
  • 是的,我可以让这些类实现一个通用接口。

标签: java generics java-8 code-reuse


【解决方案1】:

定义你的界面

您可以创建一个将由MyClass实现的接口

public interface LocationAware {
    String getName();
    void setName(String name);
    List<International> getInternationals();
    void setInternationals(List<International> internationals);
}

然后像这样实现类

public static class MyClass implements LocationAware {
    private String name;
    private List<International> internationalList;
    // getter and setters
}

您还可以使用International 的接口并实现该类。

public interface International {
    String getLanguage();
    String getTranslation();
}

使用辅助方法

并且您可以在任何您想要的类中使用带有泛型的辅助方法,例如StaticClass.

public static <T extends LocationAware> T changeLocationName(String local, T object) {
    for (International international : object.getInternationals()) {
        if(local.equals(international.getLanguage())) {
            object.setName(international.getTranslation());
        }
    }
    return object;
}

可以这样调用:

StaticClass.changeLocationName("en-us", myClass);

使用默认方法

由于您已经在使用接口,因此您可以拥有一个默认方法,无需辅助方法即可为您提供相同的功能。

public interface LocationAware {
    default void changeLocationName(String local) {
        for (International international : getInternationals()) {
            if(local.equals(international.getLanguage())) {
                setName(international.getTranslation());
            }
        }
    }
    String getName();
    void setName(String name);
    List<International> getInternationals();
    void setInternationals(List<International> internationals);
}

并且只需使用类方法:

MyClass myClass = new Myclass(); // create and add name and internationals
myClass.changeLocationName("en-us"); // then change the location

在这里你可以决定如何处理local的许多其他方式,例如,你可以存储值,当你使用getName()时,动态地返回当前名称,所以你不会更改当前名称每次,(也可以使用地图来获得很少的性能提升)。

public interface LocationAware {
    default String getName() {
        return getInternationals().get(getLocal());
    }
    void setName(String local);
    String getLocal();
    void setLocal(String local);
    Map<String, International> getInternationals();
    void setInternationals(Map<String, International> internationals);
}

注意:你应该处理位置不存在的情况

【讨论】:

    【解决方案2】:

    这是一个解决问题的静态方法,无需泛型。

    public static String lookUpName(String locale, String List<International> list) {
      for (International international : list) {
        if (local.equals(international.language) {
          return international.translation;
        }
      }
      return null; //or “” if that is preferred 
    }
    

    【讨论】:

      【解决方案3】:

      这可能被视为更多的评论,但我想添加足够的细节,这不适合评论。

      尚不清楚哪个类包含myMethod(...),但该方法似乎支持外部来自包含数据的MyClass 的国际化。这违反了告诉不要问的原则。

      一种更面向对象的方法是让MyClass 知道如何进行自己的翻译。例如:

      public class NameTranslator {
         // constructor loads the List (or Map)
      
          public String translate(String locale, String name) {
             ...
          }
      }
      

      MyClass 知道它的语言环境并使用翻译器:

      public class MyClass {
          private final NameTranslator translator;
          private final String locale;
          private String name;
      
          // constructor to set the translator and locale
      
          public void setName(String name) {
             String translatedName = translator.translate(locale, name);
             if (translatedName != null) {
               this.name = translatedName;
             } else {
               this.name = name;  // or throw an IllegalStateException?
             }
          }
      
          public String getName() {
            return name;
          }
      }
      

      所以翻译者不需要知道任何关于MyClass 或任何其他类的信息。

      此外,在搜索要翻译的项目时,地图会比列表更快。

      【讨论】:

        【解决方案4】:

        定义一个普通的合约,比如

        public interface CommonInterface {
            String getName();
            void setName(String name);
            List<International> getInternational();
        }
        

        让所有类都实现它。这是一个这样的课程。

        public class MyClass implements CommonInterface {
            private String name;
            private List<International> internationalList;
        
            @Override
            public String getName() {
                return name;
            }
        
            @Override
            public void setName(String name) {
                 this.name = name;
            }
        
            @Override
            public List<International> getInternational() {
                return internationalList; //Or create a defensive copy
            }
        }
        

        您的常用方法如下所示

        public <T extends CommonInterface> T myMethod(String local, T myObject) {
            for (International international : myObject.getInternational()){
                if(local.equals(international.language)) { //Better to avoid direct access and include getters in International class
                    myObject.setName(international.translation);
                }
            }
            return myObject;
        }
        

        【讨论】:

          【解决方案5】:

          创建一个抽象类,将方法“MyMethod”标记为静态,并从您需要的类中以静态方式调用它。一个简单的解决方案。

          【讨论】:

            猜你喜欢
            • 2018-07-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-09-05
            • 2011-07-01
            • 1970-01-01
            • 2021-02-18
            • 1970-01-01
            相关资源
            最近更新 更多