Вопрос

Какие факторы определяют, какой подход является более подходящим?

Это было полезно?

Решение

Я думаю, что у обоих есть свои места.

Вы не должны просто использовать DoSomethingToThing(Thing n) просто потому, что вы считаете, что "Функциональное программирование - это хорошо".Точно так же вы не должны просто использовать Thing.DoSomething() потому что "Объектно-ориентированное программирование - это хорошо".

Я думаю, все сводится к тому, что вы пытаетесь донести.Перестаньте думать о своем коде как о серии инструкций и начните думать о нем как о абзаце или предложении истории.Подумайте о том, какие части являются наиболее важными с точки зрения поставленной задачи.

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

Пример:

fileHandle.close();

Большую часть времени, когда вы передаете дескрипторы файлов, главное, о чем вы думаете, - это отслеживание файла, который он представляет.

Контрпример:

string x = "Hello World";
submitHttpRequest( x );

В этом случае отправка HTTP-запроса гораздо важнее, чем строка, которая является телом, поэтому submitHttpRequst(x) предпочтительнее, чтобы x.submitViaHttp()

Излишне говорить, что они не являются взаимоисключающими.Вероятно, у вас действительно будет

networkConnection.submitHttpRequest(x)

в котором вы смешиваете их оба.Важно, чтобы вы подумали о том, какие части подчеркнуты и что вы будете передавать будущему читателю кода.

Другие советы

Чтобы быть объектно-ориентированным, рассказывайте, а не спрашивайте : http://www.pragmaticprogrammer.com/articles/tell-dont-ask.

Итак, Вещь.doSomething() вместо DoSomethingToThing(Вещь n).

Если вы имеете дело с внутренним состоянием вещи, то Вещь.Функция doSomething() имеет больше смысла, потому что даже если вы измените внутреннее представление Thing или то, как оно работает, код, взаимодействующий с ним, не должен меняться.Если вы имеете дело с набором вещей или пишете какие-то служебные методы, метод DoSomethingToThing() в процедурном стиле может иметь больше смысла или быть более простым;но, тем не менее, обычно может быть представлен в виде метода для объекта, представляющего эту коллекцию:например

GetTotalPriceofThings();

против

Cart.getTotal();

Это действительно зависит от того, насколько объектно-ориентирован ваш код.

  1. Вещь.Сделай что-нибудь уместно, если предметом вашего предложения является Вещь.
    • doSomething ничего не значит (Вещь n) уместно, если объектом вашего предложения является Вещь.
    • Вещь.Досомет чего-то большего (ThingB m) это неизбежная комбинация, поскольку во всех языках, которые я могу придумать, функции принадлежат одному классу и не принадлежат друг другу.Но это имеет смысл, потому что у вас может быть субъект и объект.

Активный залог более понятен, чем пассивный, поэтому убедитесь, что в вашем предложении есть подлежащее, а не просто "компьютер".Это означает, что используйте форму 1 и форму 3 часто, а форму 2 - редко.

Для ясности:

// Form 1:  "File handle, close."
fileHandle.close(); 

// Form 2:  "(Computer,) close the file handle."
close(fileHandle);

// Form 3:  "File handle, write the contents of another file handle."
fileHandle.writeContentsOf(anotherFileHandle);

Я согласен с Орионом, но я собираюсь перефразировать процесс принятия решений.

У вас есть существительное и глагол / объект и действие.

  • Если многие объекты этого типа будут использовать это действие, попробуйте сделать действие частью объекта.
  • В противном случае попробуйте сгруппировать действие отдельно, но со связанными действиями.

Мне нравятся примеры файлов / строк.Существует много строковых операций, таких как "SendAsHTTPReply", которые не будут выполняться для вашей обычной строки, но часто происходят при определенных настройках.Тем не менее, вы в принципе всегда будете закрывать файл (надеюсь), поэтому имеет смысл поместить действие Закрытия в интерфейс класса.

По-другому об этом можно подумать как о покупке части развлекательной системы.Имеет смысл использовать пульт дистанционного управления в комплекте с телевизором, потому что вы всегда используете их вместе.Но было бы странно подключать кабель питания для конкретного видеомагнитофона к телевизору, поскольку многие клиенты никогда этим не воспользуются.Ключевая идея заключается в следующем как часто это действие будет использоваться для данного объекта?

Здесь и близко недостаточно информации.Это зависит от того, поддерживает ли ваш язык вообще конструкцию "Thing.something" или эквивалентную (т.е.это ОО-язык).Если это так, то это гораздо более уместно, потому что это парадигма OO (члены должны быть связаны с объектом, на который они воздействуют).В процедурном стиле, конечно, DoSomethingtoThing() - ваш единственный выбор...или ThingDoSomething()

DoSomethingToThing(Thing n) был бы скорее функциональным подходом, тогда как Thing.doSomething() был бы скорее объектно-ориентированным подходом.

Это выбор между объектно-ориентированным и Процедурным программированием :)

Я думаю, что хорошо документированные преимущества OO применимы и к этой вещи.doSomething()

Вот несколько факторов, которые следует учитывать:

  • Можете ли вы изменить или расширить Thing класс.Если нет, используйте первое
  • Может Thing будет создан экземпляр.Если нет, используйте later в качестве статического метода
  • Если Thing фактически модифицируется (т.е.обладает свойствами, которые изменяются), отдают предпочтение последнему.Если Thing не модифицируется, последнее столь же приемлемо.
  • В противном случае, поскольку объекты предназначены для сопоставления с объектами реального мира, выберите метод, который кажется более обоснованным в реальности.

Даже если вы не работаете на языке OO, где у вас было бы Thing.doSomething(), для общей читаемости вашего кода, имеет набор функций, таких как:

Что-то вроде чего-то () Что-то вроде другой задачи () Что-то вроде чего-то другого ()

тогда

Another thingdosomething() Другое нечто()

и так далее гораздо лучше.

Весь код, который работает с "Thing", находится в одном месте.Конечно, "doSomething" и другие задачи должны называться последовательно - так что у вас есть ThingOneRead(), ThingTwoRead()...к этому моменту вы должны получить очко.Когда вы вернетесь к работе над кодом через двенадцать месяцев, вы будете благодарны за то, что потратили время на то, чтобы все было логично.

В общем, если "что-то" - это действие, которое "вещь", естественно, знает, как выполнять, то вам следует использовать thing .doSomething() .Это хорошая инкапсуляция OO, потому что в противном случае DoSomethingToThing(thing) должен был бы получить доступ к потенциальной внутренней информации "thing".

Например, invoice.getTotal()

Если "что-то" естественным образом не является частью модели предметной области "thing", то одним из вариантов является использование вспомогательного метода.

Например:Logger.log(счет-фактура)

Если выполнение чего-либо с объектом, вероятно, приведет к другому результату в другом сценарии, тогда я бы предложил вам что-то одно.DoSomethingToThing(другое).

Например, у вас может быть два способа сохранения thing в вашей программе, поэтому вы могли бы использовать DatabaseObject.Save(вещь) SessionObject.Save(вещь) было бы более выгодно, чем thing.Save() или вещь.SaveToDatabase или вещь.SaveToSession().

Я редко не передаю никаких параметров классу, если только я не извлекаю общедоступные свойства.

Чтобы добавить к ответу Aeon, это зависит от самой вещи и того, что вы хотите с ней сделать.Итак, если вы пишете Thing, и doSomething изменяет внутреннее состояние Thing, то лучшим подходом является Thing.doSomething.Однако, если действие делает больше, чем просто изменяет внутреннее состояние, тогда doSomething (Вещь) имеет больше смысла.Например:

Collection.Add(Thing)

это лучше, чем

Thing.AddSelfToCollection(Collection)

И если вы не писали Thing и не можете создать производный класс, то у вас нет выбора, кроме как сделать doSomething(Вещь)

Даже в объектно-ориентированном программировании может быть полезно использовать вызов функции вместо метода (или, если уж на то пошло, вызывать метод объекта, отличный от того, для которого мы его вызываем).Представьте себе простую платформу сохранения базы данных, в которой вы хотели бы просто вызвать save() для объекта.Вместо того чтобы включать инструкцию SQL в каждый класс, который вы хотели бы сохранить, тем самым усложняя код, распространяя SQL по всему коду и превращая изменение механизма хранения в PITA, вы могли бы создать интерфейс, определяющий save(Class1), save (Class2) и т.д.и его реализация.Тогда вы действительно вызвали бы databaseSaver.save(class1) и собрали бы все в одном месте.

Я должен согласиться с Кевин Коннер

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top