【问题标题】:Generic or abstract class?通用类还是抽象类?
【发布时间】:2013-02-12 09:53:15
【问题描述】:

我的应用程序中有三个类UserGroupCompany,它们不属于同一个继承树,正如它们的名称所示。每个类都有一个构造函数,它接收许多(不同的)参数,即:User(String name, String password, int type)Group(String name, String name)Company(String name, int employees, boolean isValid)。对于所有类,每个构造函数所需的参数数量并不相同。我创建了一个类 ReadDataFromFile 来从 txt 文件中读取一些数据并创建新的对象,将数据作为参数传递给上述构造函数。这个类的代码对于每种类型显然都是相同的,除了一个创建对象的方法。因此,创建三个不同的类是不合适的,但我最好以更好的设计方法为目标。

我的问题是,这个场合的合适设计是通用类还是抽象类,并在其子类中实现与 createObject() 不同的一个方法,假设来自 txt 文件的必要数据被放入每种类型的长度不同的字符串数组。我想遵循通用类的方法:class ReadDataFromFile<T>{},但我找不到应该如何处理不同类型,因为每个类型都需要调用不同的构造函数。我应该检查instanceof 的类型吗?我应该将每个对象的类传递给方法吗?或者,还有更好的方法?

【问题讨论】:

  • 也许你正在修复一些没有损坏的东西。

标签: java oop generics abstract-class


【解决方案1】:

不明白您为什么将问题提出为“抽象通用”,看起来常见的解决方案是两者兼而有之。

public abstract class ReadFromFile<T> {

  public T readFile(File file) {
    String[] rawInput = doSomeStuffCommonToAll();
    return constructObject(rawInput);
  }

  abstract T constructObject(String[] rawInput);
}

public class UserFileReader extends ReadFromFile<User> {

  @Override
  User constructObject(String[] rawInput) {
    return new User(rawInput[0], rawInput[1], Integer.parseInt(rawInput[2]);
  }
}

【讨论】:

  • 这似乎是一个不错的解决方案。我会试试看。我想如果它是一种只使用泛型来避免创建四个类的方法。
  • 泛型是 Java 中的仅编译时特性。他们无法为您解决根据 run-time 输入选择要执行的代码路径的问题。
【解决方案2】:

根据条件创建对象,例如“instanceof”验证:

if (objectData instanceof User){
 User = new User();
 user.setName(objectData.getString(1));
} //...

【讨论】:

  • 什么解释了原始输入以创建 objectData 作为 User 的实例?
【解决方案3】:

我想我会选择抽象设计,例如使用抽象工厂模式。

【讨论】:

    【解决方案4】:

    简而言之,两者都不是 :) 是的,您确实需要抽象,但它不一定是您似乎倾向于的子类化形式。 Prefer composition over inheritance?

    长答案 :) 我不完全了解您的域,但根据您所写的内容,我假设您有三个文件,users.txt、groups.txt 和 company.txt,它们具有共享格式但具有不同的数据- 类似 CSV 的东西。所以你可以通过做这样的事情通过组合来实现抽象,即使我的假设是错误的,这也应该说明这一点。

    public class FileReader {
        public static void read(File f, RowHandler rowHandler) {
            //read each line, convert its contents to a map, and pass it to rowHandler
        }
    }
    

    在哪里

    public interface RowHandler {
        void handle(Map<String,String> row);
    }
    

    这意味着您将每行的读取和解析与对每行解析的操作分开。

    要创建用户对象,您可以这样做:

    public class UserConstructor implements RowHandler {
        private List<User> users = new ArrayList<User);
    
        public void handle(Map<String,String> row) {
            users.add(new User(row.get("name"), row.get("password"), Integer.parseInt(row.get("type)));
        }
    
        public List<User> getUsers() {
            return users;
        }
    }
    

    然后你把它连接起来

    UserConstructor uc = new UserConstructor();
    FileReader.readFile(new File("users.txt), uc);
    List<User> users = uc.users();
    

    您使用类名 ReadDataFromFile。这个名字暗示了一个单一的目的,但你的问题表明你正在将另一个问题混入其中 - 所以它会读取文件并创建对象。 ReadDataFromFile 应该只是从文件中读取数据,并将数据传递给另一个类以实现对其进行处理的策略。

    这就是上述设计试图做的——将关注点分开。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 2013-01-02
      • 2021-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多