将属性存储在实例变量中还是用方法计算?

问题描述 投票:0回答:2

我第一次遇到的是这样的:在一个 Box 类,有一个包含项目的列表。所有这些项目都有一个 int weight 实例变量。现在,为了得到 Box在这里,我们应该使用一个实例变量 weight 来跟踪这些?或者你应该使用一个方法 calculateWeight() 来获取权重?

public class Box {
    private ArrayList<Item> list; // Item objects in the list, all Item objects have a weight
    private int weight; // Should I: use an instance variable as is seen here <- ?

    public int calculateWeight() { // or use a method to calculate the weight each time?
       int sum = 0;
       // for all items get the weight and add it together
       return sum;
    }
}

在这个例子中,我觉得使用方法比使用实例变量更有意义,因为否则实例变量 weightBox 每次添加或删除一个项目时都必须更新。

但现在我正在做一个可读性得分计算器(JetBrains上的项目),我发现我应该做什么不太清楚。可读性得分计算器是将一篇文章的句子、单词、字符、音节等数量计算出来,然后用一个简单的公式来计算可读性得分。目前,我一直通过调用构造函数中的计算方法,将所有的句子、单词、字符等数量存储在实例变量中,但我不确定这是否是一个好的做法(我觉得有些混乱)。另一种选择是干脆不把它们存储在实例变量中,只在每次需要的时候使用方法来获取金额。这就是现在的代码。

public abstract class ReadabilityScoreCalculator {
    protected String name;
    protected String text;
    protected int wordCount;
    protected int sentenceCount;
    protected int charCount;
    protected int syllableCount;
    protected int polySyllableCount;
    protected double score;
    protected int age;

    public ReadabilityScoreCalculator(String text, String name) {
        this.text = text;
        this.name = name;
        this.wordCount = this.countWords();
        this.sentenceCount = this.countSentences();
        this.charCount = this.countCharacters();
        this.syllableCount = this.countSyllables();
        this.polySyllableCount = this.countPolySyllables();
        this.score = this.calculateAndReturnScore();
        this.age = this.getAgeGroup();
    }

     private int countWords() {
        return this.getArrayOfWords().length;
    }

     private String[] getArrayOfWords() {
         return this.text.split("[ ]+");
     }

    private int countSentences() {
        return this.text.split("[.!?]").length;
    }

    private int countCharacters() {
        String textWithoutSpaces = this.removeSpaces();
        return textWithoutSpaces.length();
    }

    private String removeSpaces() {
        return this.text.replaceAll("[ ]+", "");
    }

    private int countSyllables() {
        String[] words = this.getArrayOfWords();
        int amountOfSyllables = Arrays.stream(words)
                .mapToInt(word -> this.countSyllablesInWord(word))
                .reduce(0, (previousCount, amountOfSyllablesInWord) -> previousCount + amountOfSyllablesInWord);
        return amountOfSyllables;
    }


    private int countSyllablesInWord(String word) {
        int amountOfSyllablesInWord = 0;
        for (int i = 0, n = word.length(); i < n; i++) {
            char character = word.charAt(i);
            if (this.isCharVowel(character)) {
                if (this.isCharVowel(word.charAt(i - 1)) || this.areWeAtTheLastCharAndDoesItEqualE(i, word)) {
                    continue;
                }
                amountOfSyllablesInWord++;
            }
        }
        return (amountOfSyllablesInWord == 0) ? 1 : amountOfSyllablesInWord;
    }

    private boolean isCharVowel(char character) {
        String charAsString = String.valueOf(character);
        return charAsString.matches("(?i)[aeiouy]");
    }

    private boolean areWeAtTheLastCharAndDoesItEqualE(int index, String word) {
        int wordLength = word.length();
        char currentCharacter = word.charAt(index);
        return (index == (wordLength - 1) && currentCharacter == 'e');
    }

    private int countPolySyllables() {
        String[] words = this.getArrayOfWords();
        int amountOfPolySyllables = Arrays.stream(words)
                .mapToInt(word -> this.countSyllablesInWord(word))
                .filter(amountOfSyllablesInWord -> amountOfSyllablesInWord > 2)
                .reduce(0, (previousCount, amountOfPolySyllablesInWord) -> previousCount + amountOfPolySyllablesInWord);
        return amountOfPolySyllables;
    }

    private double calculateAndReturnScore() {
        return this.calculateScore();
    }

    abstract double calculateScore();

    public void setScore(double score) {
        this.score = score;
    }

    public void printResults() {
        System.out.println(this.name + ": " + this.score + " (about " + this.age + " year olds).");
    }

    public void setAgeGroup() {
        this.age = this.getAgeGroup();
    }

    private int getAgeGroup() {
        int ageGroup = 0;
        switch(this.roundUpAndParseToInt(this.score)) {
            case 1:
                ageGroup = 6;
                break;
            case 2:
                ageGroup = 7;
                break;
            case 3:
                ageGroup = 9;
                break;
            case 4:
                ageGroup = 10;
                break;
            case 5:
                ageGroup = 11;
                break;
            case 6:
                ageGroup = 12;
                break;
            case 7:
                ageGroup = 13;
                break;
            case 8:
                ageGroup = 14;
                break;
            case 9:
                ageGroup = 15;
                break;
            case 10:
                ageGroup = 16;
                break;
            case 11:
                ageGroup = 17;
                break;
            case 12:
                ageGroup = 18;
                break;
            case 13:
                ageGroup = 24;
                break;
            case 14:
                ageGroup = 24;
                break;
        }
        return ageGroup;
    }

    public int roundUpAndParseToInt(double number) {
        return (int) Math.ceil(number);
    }


}

其中一个或另一个是否被认为是好的做法?还是真的要看情况而定?我可以看到,方法的方式在计算上会更昂贵,但却能提供更多的确定性。我上面的代码还有什么问题也可以叫出来。

编辑:这是个抽象类,而这个 calculateScore() 方法应该由继承自这个类的类来填写。因此,可以使用多个不同的公式来计算可读性分数。

java methods instance-variables
2个回答
0
投票

一般来说,省略使用基于计算的实例变量,而采用方法进行检索。更重要的是你的代码是否简明扼要地记录了自己,是否易于维护。

通过使用实例变量,每次修改它们各自的属性时,你都需要更新它们,这会使你修改这些变量的方法的可读性变得模糊不清。

例如,这里有几个简单的方法,可以修改 list 并更新 weight 成员变量。

public void addItem(Item item) {
    this.list.add(item);
    this.weight += item.weight;
}

public Item removeItem(int i) {
    Item item = this.list.remove(i);
    this.weight -= item.weight;
    return item;
}

public void setList(ArrayList<Item> list) {
    this.list = list;
    this.weight = this.calculateWeight();
}

因为你在执行一个额外的操作,那就是: 方法名称中描述的,这些方法不是自我记录的。你可以把它们叫做类似于 addItemAndUpdateWeight()但如果有更多的成员变量需要更新呢?addItemAndUpdateMemberVariables() 太模糊了,很快这些方法就会变得非常混乱和难以维护。

可以 添加一个帮助函数来更新你的成员变量,但你仍然需要在每一个这样的方法中调用它,而且每次你添加一个新的成员变量时,你也必须更新这个方法。

另外,如果这些方法很昂贵,最好只在需要的时候才执行计算。

更好的解决方案是通过隔离你的方法的功能来保持简单。

public void addItem(Item item) {
    this.list.add(item);
}

public Item removeItem(int i) {
    return this.list.remove(i);
}

public void setList(ArrayList<Item> list) {
    this.list = list;
}

马上,你就知道这些方法是做什么的, 而且没有偷偷摸摸的代码让你以后头疼。另外,现在你不需要在你的构造函数中执行这些操作。

我相信,对于更复杂的情况,比如索引,可以有一个案例,但这似乎超出了这次讨论的范围。

© www.soinside.com 2019 - 2024. All rights reserved.