Java,重构案例

时间:2017-06-15 13:30:39

标签: java refactoring

我得到了运动,我需要重构几个java项目 只有那些我遗忘的人才不知道如何重构。

csv.writer

public class CsvWriter {
public CsvWriter() {
}

public void write(String[][] lines) {
    for (int i = 0; i < lines.length; i++)
        writeLine(lines[i]);
}

private void writeLine(String[] fields) {
    if (fields.length == 0)
        System.out.println();
    else {
        writeField(fields[0]);

        for (int i = 1; i < fields.length; i++) {
            System.out.print(",");
            writeField(fields[i]);
        }
        System.out.println();
    }
}

private void writeField(String field) {
    if (field.indexOf(',') != -1 || field.indexOf('\"') != -1)
        writeQuoted(field);
    else
        System.out.print(field);
}

private void writeQuoted(String field) {
    System.out.print('\"');
    for (int i = 0; i < field.length(); i++) {
        char c = field.charAt(i);
        if (c == '\"')
            System.out.print("\"\"");
        else
            System.out.print(c);
    }
    System.out.print('\"');
}
}

csv.writertest

public class CsvWriterTest {

@Test
public void testWriter() {
    CsvWriter writer = new CsvWriter();
    String[][] lines = new String[][] {
            new String[] {},
            new String[] { "only one field" },
            new String[] { "two", "fields" },
            new String[] { "", "contents", "several words included" },
            new String[] { ",", "embedded , commas, included",
                    "trailing comma," },
            new String[] { "\"", "embedded \" quotes",
                    "multiple \"\"\" quotes\"\"" },
            new String[] { "mixed commas, and \"quotes\"", "simple field" } };

    // Expected:
    // -- (empty line)
    // only one field
    // two,fields
    // ,contents,several words included
    // ",","embedded , commas, included","trailing comma,"
    // """","embedded "" quotes","multiple """""" quotes"""""
    // "mixed commas, and ""quotes""",simple field

    writer.write(lines);
}
}

测试

public class Configuration {
public int interval;

public int duration;

public int departure;

public void load(Properties props) throws ConfigurationException {
    String valueString;
    int value;

    valueString = props.getProperty("interval");
    if (valueString == null) {
        throw new ConfigurationException("monitor interval");
    }
    value = Integer.parseInt(valueString);
    if (value <= 0) {
        throw new ConfigurationException("monitor interval > 0");
    }
    interval = value;

    valueString = props.getProperty("duration");
    if (valueString == null) {
        throw new ConfigurationException("duration");
    }
    value = Integer.parseInt(valueString);
    if (value <= 0) {
        throw new ConfigurationException("duration > 0");
    }
    if ((value % interval) != 0) {
        throw new ConfigurationException("duration % interval");
    }
    duration = value;

    valueString = props.getProperty("departure");
    if (valueString == null) {
        throw new ConfigurationException("departure offset");
    }
    value = Integer.parseInt(valueString);
    if (value <= 0) {
        throw new ConfigurationException("departure > 0");
    }
    if ((value % interval) != 0) {
        throw new ConfigurationException("departure % interval");
    }
    departure = value;
}

}

 public class ConfigurationException extends Exception {

private static final long serialVersionUID = 1L;

public ConfigurationException() {
    super();
}

public ConfigurationException(String arg0) {
    super(arg0);
}

public ConfigurationException(String arg0, Throwable arg1) {
    super(arg0, arg1);
}

public ConfigurationException(Throwable arg0) {
    super(arg0);
}

}

configuration.test

 public class ConfigurationTest{

@Test
public void testGoodInput() throws IOException {
    String data = "interval = 10\nduration = 100\ndeparture = 200\n";

    Properties input = loadInput(data);

    Configuration props = new Configuration();
    try {
        props.load(input);
    } catch (ConfigurationException e) {
        assertTrue(false);
        return;
    }

    assertEquals(props.interval, 10);
    assertEquals(props.duration, 100);
    assertEquals(props.departure, 200);
}
@Test
public void testNegativeValues() throws IOException {
    processBadInput("interval = -10\nduration = 100\ndeparture = 200\n");
    processBadInput("interval = 10\nduration = -100\ndeparture = 200\n");
    processBadInput("interval = 10\nduration = 100\ndeparture = -200\n");
}
@Test
public void testInvalidDuration() throws IOException {
    processBadInput("interval = 10\nduration = 99\ndeparture = 200\n");
}
@Test
public void testInvalidDeparture() throws IOException {
    processBadInput("interval = 10\nduration = 100\ndeparture = 199\n");
}
@Test
private void processBadInput(String data) throws IOException {
    Properties input = loadInput(data);

    boolean failed = false;
    Configuration props = new Configuration();
    try {
        props.load(input);
    } catch (ConfigurationException e) {
        failed = true;
    }

    assertTrue(failed);
}
@Test
private Properties loadInput(String data) throws IOException {
    InputStream is = new StringBufferInputStream(data);

    Properties input = new Properties();
    input.load(is);
    is.close();

    return input;
}
}

提前谢谢你,对不起我的英语。

1 个答案:

答案 0 :(得分:0)

好的,这里有一些关于代码的建议。

<强> CsvWriter

  • 糟糕的是您将所有内容打印到System.out。没有嘲笑就很难测试。相反,我建议您添加字段PrintStream,它定义所有数据的去向。

    import java.io.PrintStream;
    
    public class CsvWriter {
    
    private final PrintStream printStream;
    
    public CsvWriter() {
        this.printStream = System.out;
    }
    
    public CsvWriter(PrintStream printStream) {
        this.printStream = printStream;
    }
    ...
    

然后您将所有内容写入此流。由于您使用替换功能(在IDEA中为Ctrl + R),因此这种重构很容易。以下是您如何操作的示例。

private void writeField(String field) {
    if (field.indexOf(',') != -1 || field.indexOf('\"') != -1)
        writeQuoted(field);
    else
        printStream.print(field);
}

其他东西在这堂课中似乎没问题。

<强> CsvWriterTest

  • 首先,您不要在单个方法中检查所有逻辑。用不同类型的测试制作小方法。可以保持当前的测试。有时在复杂场景中检查大多数逻辑是有用的。
  • 还要注意方法的名称。查看this
  • 显然你测试不检查结果。这就是为什么我们需要PrintStream的这个功能。我们可以在ByteArrayOutputStream的实例之上构建一个PrintStream。然后我们构造一个字符串并检查内容是否有效。以下是如何轻松查看所写内容的方法

    public class CsvWriterTest {
    
    private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    private PrintStream printStream = new PrintStream(byteArrayOutputStream);
    
    @Test
    public void testWriter() {
        CsvWriter writer = new CsvWriter(printStream);
        ... old logic here ...
        writer.write(lines);
    
        String result = new String(byteArrayOutputStream.toByteArray());
        Assert.assertTrue(result.contains("two,fields"));
    

    <强>配置

  • 将字段设为私有
  • 让消息更简洁

<强>的ConfigurationException 似乎很好的serialVersionUID。序列化/反序列化需要这个东西。

<强> ConfigurationTest

  • 不要使用assertTrue(false / failed);使用Assert.fail(String)和一些可以理解的消息。

提示:如果您没有太多经验并且需要重构这样的代码,您可能需要阅读Joshua Bloch撰写的Effective Java 2nd edition的一些章节。这本书不是很大,所以你可以在一周内阅读它,它有一些规则如何编写干净,易懂的代码。