为其他开发人员设计用于java的类

为其他开发人员设计用于java的类,java,Java,我立即看到以下问题: -开发人员必须在getOutput之前先调用read。他无法凭直觉知道这一点,这可能是一个糟糕的设计 因此,我决定修复代码并编写如下内容 CSVReader reader = new CVSReader(new FileInputStream("test.csv"); reader.read(); read.getOutput(); 还是这个 public List<String> getOutput() { if(output==null) thro

我立即看到以下问题: -开发人员必须在getOutput之前先调用read。他无法凭直觉知道这一点,这可能是一个糟糕的设计

因此,我决定修复代码并编写如下内容

CSVReader reader = new CVSReader(new FileInputStream("test.csv");
reader.read();
read.getOutput();
还是这个

public List<String> getOutput() {
if(output==null) 
   throw new IncompleteStateException("invoke read before getoutput()");
return Collections.unmodifiableList(output);
}
public CSVReader(InputStream input) {
read(); //throw runtime exception
}
public List read()引发IOException{
//读取并创建输出列表。
//返回列表
}

实现目标的好方法是什么?对象状态是否应始终定义良好从来没有一种状态是不定义“输出”的,所以我应该创建输出作为构造函数的一部分?或者,该类是否应该通过在发现未定义“输出”时调用“读取”并仅抛出运行时异常来确保创建的实例始终有效?这里的好方法/最佳实践是什么

我建议您将类尽可能小,同时删除
getOutput()
方法

其想法是让一个类读取CSV文件并返回一个表示结果的列表。为了实现这一点,您可以公开一个
read()
方法,该方法将返回一个
列表

比如:

public List<String> read() throws IOException {
//read and create output list.
// return list
}
公共类CSVReader{
私有最终输入流输入;
公共CSVReader(字符串文件名){
this.input=新文件输入流(文件名);
}
公共列表读取(){
//在此处执行实际读数
}
}

您有一个定义良好的类,需要维护一个小接口,
CSVReader
的实例是不可变的。

我建议您将类尽可能小,同时删除
getOutput()
方法

其想法是让一个类读取CSV文件并返回一个表示结果的列表。为了实现这一点,您可以公开一个
read()
方法,该方法将返回一个
列表

比如:

public List<String> read() throws IOException {
//read and create output list.
// return list
}
公共类CSVReader{
私有最终输入流输入;
公共CSVReader(字符串文件名){
this.input=新文件输入流(文件名);
}
公共列表读取(){
//在此处执行实际读数
}
}
您有一个定义良好的类,需要维护一个小接口,
CSVReader
的实例是不可变的

  • 第一种方法剥夺了API的一些灵活性:在进行更改之前,用户可以在预期出现异常的上下文中调用
    read()
    ,然后调用
    getOutput()
    exception free()
  • 任意次数。您的更改强制用户在以前不需要的上下文中捕获选中的异常
  • 第二种方法是首先应该如何做:因为调用
    read()
    是调用
    getOutput()
    的先决条件,所以当用户“忘记”调用
    read()
    时,类有责任“捕获”用户
  • 第三种方法隐藏了
    IOException
    ,这可能是要捕获的合法异常。没有办法让用户知道是否要抛出异常,这在设计运行时异常时是一种不好的做法
  • 问题的根本原因是该类有两个相互正交的职责:

    • 读取CSV,以及
    • 存储读取的结果以供以后使用
    如果您将这两项职责相互分离,您将得到一个更干净的设计,在该设计中,用户将不会对他们必须调用的内容和顺序产生混淆:

    public class CSVReader {
    
        private final InputStream input;
    
        public CSVReader(String filename) {
            this.input = new FileInputStream(filename);
        }
    
        public List<String> read() {
            // perform the actual reading here
        }
    }
    
    接口CSVData{
    List getOutput();
    }
    CSVReader类{
    公共静态CSVData读取(InputStream输入)引发IOException{
    ...
    }
    }
    
    您可以使用工厂方法将这两个类组合成一个类:

    interface CSVData {
        List<String> getOutput();
    }
    class CSVReader {
        public static CSVData read(InputStream input) throws IOException {
            ...
        }
    }
    
    类CSVData{
    私有CSVData(){//无用户实例化
    }
    //获取数据是无异常的
    公共列表getOutput(){
    ...
    }
    //创建实例需要工厂调用
    公共静态CSVData读取(InputStream输入)引发IOException{
    ...
    }
    }
    
  • 第一种方法剥夺了API的一些灵活性:在进行更改之前,用户可以在预期出现异常的上下文中调用
    read()
    ,然后调用
    getOutput()
    exception free()
  • 任意次数。您的更改强制用户在以前不需要的上下文中捕获选中的异常
  • 第二种方法是首先应该如何做:因为调用
    read()
    是调用
    getOutput()
    的先决条件,所以当用户“忘记”调用
    read()
    时,类有责任“捕获”用户
  • 第三种方法隐藏了
    IOException
    ,这可能是要捕获的合法异常。没有办法让用户知道是否要抛出异常,这在设计运行时异常时是一种不好的做法
  • 问题的根本原因是该类有两个相互正交的职责:

    • 读取CSV,以及
    • 存储读取的结果以供以后使用
    如果您将这两项职责相互分离,您将得到一个更干净的设计,在该设计中,用户将不会对他们必须调用的内容和顺序产生混淆:

    public class CSVReader {
    
        private final InputStream input;
    
        public CSVReader(String filename) {
            this.input = new FileInputStream(filename);
        }
    
        public List<String> read() {
            // perform the actual reading here
        }
    }
    
    接口CSVData{
    List getOutput();
    }
    CSVReader类{
    公共静态CSVData读取(InputStream输入)引发IOException{
    ...
    }
    }
    
    您可以使用工厂方法将这两个类组合成一个类:

    interface CSVData {
        List<String> getOutput();
    }
    class CSVReader {
        public static CSVData read(InputStream input) throws IOException {
            ...
        }
    }
    
    类CSVData{
    私有CSVData(){//无用户实例化
    }
    //获取数据是无异常的
    公共列表getOutput(){
    ...
    }
    //创建实例需要工厂调用
    公共静态CSVData读取(InputStream输入)引发IOException{
    ...
    }
    }
    
    拥有
    getOutputpublic List<String> getOutput() {
       if (output == null) { 
          try {
            output = read();
          } catch (IOException) {
            //here you either wrap into your own exception and then declare it in the signature of getOutput, or just not catch it and make getOutput `throws IOException`
          }
       }
       return Collections.unmodifiableList(output);
    }