Я имею тенденцию создавать очень большие классы, которые имеют 30-40 (или более) методов. Сколько методов слишком много? Существуют ли какие-либо "запахи" или эмпирические правила?
Когда класс слишком велик?
Ответ 1
Шаг первый заключается в том, чтобы придерживаться принципа Single Responsibility. Если вы не можете сказать в одном предложении, что делает ваш класс, то это, вероятно, слишком много.
Как только вы сузили это, я не знаю, что количество методов действительно имеет значение, пока ваши методы не делают слишком много.
Ответ 2
Я буду кусать. Не делая гораздо больше, чем пробираться по очень мелким краям глубоких вод конструкции O-O, я воспользуюсь несколькими своими правилами:
-
Статические свойства очень сомнительны. Внимательно спросите себя, действительно ли они нужны.
-
Большинство свойств/атрибутов класса должны быть частными (доступными только экземпляром объекта) или защищенными, доступными только экземпляром класса или производного класса (подкласса).
-
Если свойство/атрибут класса видимо для широкой публики, оно скорее всего будет доступно только для чтения. По большей части состояние экземпляра объекта должно изменяться только путем его ответа на метод, попросив его сделать что-то полезное (например, вы просите, чтобы окно двигалось самостоятельно, а не явно задано, происходит на плоскости координат).
-
Способы или свойства Public Getter/Setter сомнительны, поскольку они в первую очередь выставляют состояние объекта (см. элемент № 2 выше).
-
Публичные методы должны в первую очередь раскрывать логические операции (сообщения), на которые реагирует экземпляр объекта. Эти операции должны быть атомарными (например, для того, чтобы объект находился в логически последовательном внутреннем состоянии, он не должен зависеть от внешних участников, отправляющих ему определенную последовательность сообщений). Состояние объекта должно изменяться, как результат ответа на эти сообщения, и должно отображаться как побочный эффект сообщения (например, допустимо окно, сообщающее о его местоположении в качестве побочного эффекта запроса на его перемещение).
Вышеупомянутое должно значительно сократить общественный интерфейс для ваших объектов.
Наконец, если у вашего объекта есть несколько сообщений, на которые он отвечает, у вас наверняка есть кандидат на рефакторинг: действительно ли это один монолитный объект или это сборка дискретных объектов? "Более чем несколько", конечно, является очень субъективным (и контекстуальным) числом - я выкину 10-12 как разумный предел.
Надеюсь, что это поможет.
Существует множество книг по дизайну, анализу и моделированию O-O.
Ответ 3
Как говорили другие, класс слишком велик, когда он пытается сделать больше одного, а нарушает принцип единой ответственности.
Отличная книга по этой и другим темам (и я настоятельно рекомендую для любого разработчика) Чистый код от Боба Мартина.
Ответ 4
статические классы, такие как Math, скорее всего, будут иметь множество методов. Было бы странно расколоть их.
Ответ 5
Общее руководство по проектированию: если разумный человек сначала реагирует на набор вещей > может быть правдоподобным: "Это слишком много", а затем слишком много <thing> s.
Ответ 6
Число методов само по себе не является надежным индикатором. Что, если 20 из них являются просто получателями имущества?
Попробуйте более конкретные показатели, хотя это всегда является решением суда. Существует список "запахов кода" здесь.
Ответ 7
Все это относительное, но обратите внимание на принцип :
В объектно-ориентированном программировании принцип единой ответственности что каждый объект должен иметь один ответственности и ответственность должна быть полностью инкапсулированный классом
Эмпирическое правило, о котором я подумал о SRP: подсчитайте ваши операции/импорт/включает. Если у вашего класса более полудюжины есть хороший шанс, что вы нарушаете SRP. Но это тоже относительная идея. Некоторые шаблоны, такие как фасады, будут нарушать это правило по необходимости. Например. как в упрощении и скрытии сложной подсистемы.
Ответ 8
Это зависит от того, можно ли разбить класс на подклассы.
Изменить: я имею в виду, что вы должны спросить себя: "применим ли этот метод к этому классу или относится ли он к подклассу?"
Например,
Class Animal - dog_bark()dog_bark() может быть перемещен в класс с именем Dog, а метод переименован в bark()
Ответ 9
Это зависит.
Если вы находитесь на Java с парами get/set для каждого поля, я не удивлен. Но если каждый из этих методов будет звездой более 100 линий, это будет запах.
Ответ 10
Никогда не бывает слишком большого класса, когда интерпретатор PHP читает ваш код, который он компилирует в один большой исполняемый черный код, поэтому разделение их не влияет на производительность.
НО:
Когда дело доходит до программирования, вам никогда не понадобится более 40 методов в одном классе, и их нужно разделить на них.
Пример
class HTTP
{
/*
* Base functions for HTTP Fetching / transferring / Sending
* so when it comes to single responsibility this would be the the fetch / set in HTTP
*/
}
тогда вы были бы более конкретны в своих подклассах, таких как
class YoutubeUploader extends HTTP
{
/*
* This class is responsible for uploading to youtube only
*/
}
class YoutubeDownload extends HTTP
{
/*
* This class is responsible for downloading to youtube only
*/
}
class CronRunner extends HTTP
{
/*
* This class is responsible for Running your HTTP Cron Tasks
*/
}
нет, если у вас не было этого BASE-класса HTTP, вам нужно было бы определить методы во всех трех подклассах для передачи данных через HTTP-протокол.
Разделение классов на отдельные обязанности дает более структурированную структуру, что приводит к меньшему количеству кода и большему результату.
Каждый ах уже упомянул: Принцип единственной ответственности, но его то, что вы действительно должны понимать.
Также существуют способы уменьшить код в классах, возьмите этот пример
class User
{
public function getUsername()
{
return $data['username'];
}
public function getPermissions()
{
return $data['permissions'];
}
public function getFirstname()
{
return $data['firstname'];
}
}
это действительно не нужно, когда вы можете сделать:
class User
{
public function __call($method,$params = array())
{
if(substr(0,3,$method) == "get")
{
$var_name = substr(3,strlen($method),$method);
return $data[$var_name];
}
}
}
Это займет автомобиль любого метода, который начинается с "get", и он берет последнюю часть строки и ищет массив.
Ответ 11
Пункт об этом взят в третьем выпуске "Эффективный С++":
Msgstr "Применить функции, не являющиеся членами, а не другие для функций-членов". Это означает, что вы должны держать свой класс разумным, потому что большие классы, как правило, трудно развернуть (не хорошо масштабировать)
Вы также можете проверить класс для веток. Если ваш класс содержит "если есть" или "переключаться", существует высокая вероятность того, что ваша ответственность класса будет расторгнута. Если это так, рефакторинг и сокращение обязанностей на более мелкие части могут привести к меньшим классам.
С наилучшими пожеланиями,
Marcin
Ответ 12
В целом класс должен быть разработан, чтобы делать одно и делать это хорошо. Теперь, с вашим примером класса Math, он может выступать в качестве фасада для разделения реализаций. Или он может быть разделен на иерархию:
public abstract class Math
{
abstract Solve(IMathPayload);
abstract CanSolve(IMathPayload);
}
public class LinearMath : Math {}
public class DifferentialEquasionMath: Math {}
Ответ 13
Одна из моих стратегий - создать класс "Handle" для каждого объекта модели данных. Поскольку ручка отвечает только за модификацию что объект данных, он следует за SRP. Если мне нужно создавать классы за пределами модификации объекта данных, по крайней мере, я знаю, что большая часть кода уже совместима с SRP.