Разбить или не разбить класс (в Java) - PullRequest
3 голосов
/ 19 июля 2009

У меня есть предложение, которое анализируется на разных этапах. Сначала я получаю некоторые атрибуты (скажем, X, Y, Z):

public class AnalyzedSentence {
    private String X;
    private String Y;
    private String Z;

    public AnalyzedSentence(String sentence) {
        extractX();
        extractY();
        extractZ();
    }

    // getters, setters
}

Затем я использую эти атрибуты для дальнейшего анализа предложения, чтобы получить другой атрибут, скажем, «XYZ», после чего я создаю следующий класс:

public class FinalSentence {

    private AnalyzedSentence data;

    private String XYZ;

    public FinalSentence(String XYZ, AnalyzedSentence data) {
        this.data = data;
        this.XYZ = XYZ;
    }

    // getters, setters
}

Рабочий процесс выглядит следующим образом:

public class SentenceAnalyzer {
    /// ...
    public FinalSentence analyze(String sentence) {
        AnalyzedSentence as = new AnalyzedSentence(sentence);  // every attribute of "as" can be calculated beforehand
        String XYZ = SpecialClass.extractXYZ(sentence, as); // extract XYZ (needs a special class), based on as
        return new FinalSentence(XYZ, as);
    }
}

В качестве альтернативы, я мог бы иметь только один класс, содержащий всю информацию, заполняющую атрибуты по мере их извлечения, что может привести к некоторым нулевым результатам. Это было бы так:

public class Sentence {

    private String X;
    private String Y;
    private String Z;    
    private String XYZ;

    public Sentence(String sentence) {
        extractX();
        extractY();
        extractZ();
    }

    public String getXYZ() {
        // with this design, this method can be called, even if XYZ was not extracted yet.
        // remember that XYZ cannot be extracted as X,Y,Z
    }

    public void setXYZ(...) {...}

    // getters, setters
}

Мой вопрос: какой дизайн предпочтительнее и почему? Если есть еще лучший способ выполнить то, что я пытаюсь сделать здесь, я бы тоже хотел это услышать.

Ответы [ 6 ]

3 голосов
/ 19 июля 2009

Лично я предпочитаю первый дизайн, один с двумя классами. Различие между анализом и результатами привлекает меня. Мне нравится думать о классах как о наборах обязанностей больше, чем о коллекциях данных, и использование двух разных классов делает ответственность каждого более ясной.

2 голосов
/ 19 июля 2009

Необходимо учитывать, являются ли в вашей проблемной области AnalyzedSentence и FinalSentence достаточно уникальными, чтобы их можно было разделить или объединить.

Очевидно, что они работают с похожими данными и тесно сотрудничают для достижения цели.

Для меня анализируемое и окончательное - это просто состояния, в которых может присутствовать Приговор, хотя это основано на моих ограниченных знаниях проблемы, над которой вы работаете, поэтому я хотел бы как-то объединить их.

Редактировать Основываясь на дополнительной информации, я думаю, что я разработал бы что-то вроде этого:

Класс Sentence инкапсулирует исходное предложение, теги и извлеченную категорию (или что бы вы ни извлекали, я предполагаю, что это категория, основанная на вашем описании), и операции, которые нужно установить, получить и извлеките эту информацию.

Класс Sentence хранит TagList, который содержит все теги, исходную строку и извлеченную категорию. Он также инкапсулирует извлечение данных, создавая Extractor и передавая ему TagList, когда данные нуждаются в извлечении (я поместил их в конструктор, но это может происходить в методе, где он вызывается, зависит от когда вам нужно извлечь данные).

Таким образом, все, что требуется для манипулирования исходным предложением, находится в классе Sentence. Конечно, вы можете знать что-то, что я не знаю, что делает этот подход неподходящим, но вот некоторый код, чтобы проиллюстрировать, что я имею в виду:

public class Sentence {

    private TagList tags    
    private String category;
    private String sentence

    public Sentence(String newSentence) {
        sentence = newSentence;
        Extractor<TagList> e = new Extractor<TagList>()
        tags = e.extractTags(sentence);
        category = new Category(tags);
    }

    public String getXYZ() {

    }

    public void setXYZ(...) {...}

    private extractTags(String s){ ...}

    // getters, setters
}


public class TagList{

    private List<String> tags;

    ....
    //rest of class definition

}
1 голос
/ 19 июля 2009

Ответ на ваш вопрос зависит от того, как вы ожидаете, что эти классы будут изменены в будущем по мере расширения или изменения требований программы.

Хорошим ориентиром для определения того, когда нужно разделить класс или присоединиться к нему, является Принцип единой ответственности : «У класса не должно быть более одной причины для изменения класса».

Также Открытый Закрытый Принцип помогает в решении, как организовать классы так, чтобы вы могли изменять поведение существующих классов, комбинируя их с новыми классами, вместо изменения существующих классов: " Программные объекты (классы, модули, функции и т. Д.) Должны быть открыты для расширения, но закрыты для модификации. "

http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

1 голос
/ 19 июля 2009

Я за создание сравнительно небольших классов, так как мне приходится бороться с работой с классами монстров из более чем 8000 линий!
Теперь класс FinalSentence кажется слишком маленьким, как пустая оболочка, упрощенный фасад для AnalyzedSentence, и его полезность не выглядит вопиющей.

0 голосов
/ 19 июля 2009

Почему бы не один метод, который возвращает проанализированные данные на основе однострочного параметра?

String analyze(String input) {...}

Меньше беспорядка, никаких побочных эффектов (все сделано в стеке), меньше шансов, что кто-то неправильно поймет API и сделает что-то странное с ним.

0 голосов
/ 19 июля 2009

Я бы пошел на один класс, потому что я бы рассматривал извлечение XYZ как одну логическую операцию с двумя шагами.

В конструкторе вы можете извлечь X, Y, Z, а затем использовать специальный класс, чтобы получить XYZ и вернуть последнее предложение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...