ООП. Выбор объектов

просто вы можете использовать это

$("#chkAll").on("click",function(){
    $("input[name=checkBoxName]").prop("checked",$(this).prop("checked"));
});
14
задан Vlad Gudim 3 July 2009 в 11:41
поделиться

10 ответов

Отчасти проблема заключается в том, что объекты реального мира не организованы аккуратно в иерархию. У каждого объекта много разных родителей. Стакан сока, безусловно, напиток, но он также является источником питания, но не каждый напиток. В стакане воды не так много питательных веществ. Точно так же есть много источников питания, кроме напитков. Но большинство языков позволяют наследовать только от одного класса. Чашка чая технически является источником энергии (он горячий, он содержит тепловую энергию), но также и аккумулятор. Есть ли у них общий базовый класс?

И, конечно, бонусный вопрос: что может помешать мне добавить сахар в свой сок, если я захочу? Физически это возможно. Но обычно это не делается. Что вы хотите смоделировать?

В конечном счете, не пытайтесь моделировать «мир». Как вы хотите, чтобы ваше приложение помогло выпить чашку чая? Какую роль в вашем приложении играет чашка чая? Какой из возможных родителей имеет смысл в вашем случае?

Если вашему приложению необходимо различать «напитки, в которые можно добавлять сахар» и «напитки, которые можно употреблять только в нетронутом виде», то у вас, вероятно, будут два разных базовых класса. Вам вообще нужен общий урок "выпивки"? Возможно, а может и нет. Бар может не заботиться о том, что это напиток, что он пригоден для питья. это продукт, который можно продавать, и в одном случае вы должны спросить покупателя, хочет ли он в нем сахар, а в другом случае в этом нет необходимости. Но базовый класс "пить" может и не понадобиться.

Но для человека, пьющего напиток, вы, вероятно, захотите выпить "напиток". базовый класс с методом Consume (), потому что это важный его аспект.

В конечном счете, помните, что ваша цель - написать работающую программу, а не написать идеальную диаграмму классов ООП. Вопрос не в том, «как я могу представить разные типы напитков в ООП», а в том, «как я могу позволить моей программе работать с разными типами напитков». Ответ мог бы заключаться в том, чтобы расположить их в иерархии классов с общим базовым классом Drink. Но это может быть и что-то совсем другое. Это может быть «относитесь ко всем напиткам одинаково, просто поменяйте название», и в этом случае одного класса будет достаточно. Или это могло быть отношение к напиткам как к еще одному виду потребляемого материала или просто как к еще одному виду жидкости, не моделируя их «питьевые» свойства.

Если вы ' При написании имитатора физики, возможно, батарея и чашка чая должны быть производными от одного и того же базового класса, поскольку для вас важно то, что оба они способны накапливать энергию. И вот сок и чай вдруг ничего не имеют общего. Они оба могут быть напитками из другого мира, но в вашем приложении? Они совершенно разные. (И, пожалуйста, не придирайтесь к тому, как сок содержит энергию. Я бы сказал стакан воды, но тогда кто-то, вероятно, обнаружит термоядерную энергию или что-то в этом роде;))

Никогда не упускайте из виду свою цель. Зачем вам в программе моделирование напитков?

И вот сок и чай вдруг ничего не имеют общего. Они оба могут быть напитками из другого мира, но в вашем приложении? Они совершенно разные. (И, пожалуйста, не придирайтесь к тому, как сок содержит энергию. Я бы сказал стакан воды, но тогда кто-то, вероятно, обнаружит термоядерную энергию или что-то в этом роде;))

Никогда не упускайте из виду свою цель. Зачем вам в программе моделирование напитков?

И вот сок и чай вдруг ничего не имеют общего. Они оба могут быть напитками из другого мира, но в вашем приложении? Они совершенно разные. (И, пожалуйста, не придирайтесь к тому, как сок содержит энергию. Я бы сказал стакан воды, но тогда кто-то, вероятно, обнаружит термоядерную энергию или что-то в этом роде;))

Никогда не упускайте из виду свою цель. Зачем вам в программе моделирование напитков?

17
ответ дан 1 December 2019 в 05:55
поделиться

Объектно-ориентированный дизайн не выполняется изолированно. Вопрос, который вы должны задать, - что мое конкретное приложение должно делать (если вообще что-либо) с классом Drink? Ответ и, следовательно, дизайн будут отличаться от приложения к приложению. Способ номер 1 потерпеть неудачу в ОО - это попытаться построить идеальную платоническую иерархию классов - такие вещи существуют только в идеальных платоновских мирах и бесполезны в реальном мире, в котором мы живем.

19
ответ дан 1 December 2019 в 05:55
поделиться

Там два решения проблемы сахара. Первый - добавить подкласс, такой как HotDrinks, который содержит addSugar и addMilk, например:

                 Drink
                  /  \
          HotDrink    Juice
           /   \
        Tea     Coffee

Проблема в том, что это становится беспорядочным, если их много.

Другое решение - добавить интерфейсы. Каждый класс может реализовывать ноль или более интерфейсов. Итак, у вас есть интерфейсы ISweetened и ICowPowerEnabled. Где и Tea, и Coffee реализуют интерфейсы ISweetened и ICowPowerEnabled.

13
ответ дан 1 December 2019 в 05:55
поделиться

Этот PDF-файл может вам очень помочь, и он идеально подходит для вашего примера:

Шаблон декоратора

4
ответ дан 1 December 2019 в 05:55
поделиться

Чтобы добавить к другим ответам, интерфейсы, как правило, дают вам большую гибкость при разделении кода.

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

Например, если вы «добавляете сахар» к напиток сегодня, вы можете решить добавить его в блин позже. И тогда вы можете закончить тем, что ваш код будет запрашивать напиток во многих местах, используя AddSugar и различные другие несвязанные методы - это может быть сложно рефакторинг.

Если ваш класс умеет что-то делать, то он может реализовать интерфейс, независимо от того, что это за класс на самом деле. Например:

interface IAcceptSugar
{
    void AddSugar();
}

public class Tea : IAcceptSugar { ... }
public class Coffee : IAcceptSugar { ... }
public class Pancake : IAcceptSugar { ... }
public class SugarAddict : IAcceptSugar { ... }

Использование интерфейса для запроса конкретной функции у объекта, который фактически ее реализует, помогает вам создавать в высшей степени независимый код.

public void Sweeten(List<IAcceptSugar> items)
{
   if (this.MustGetRidOfAllThisSugar)
   {
       // I want to get rid of my sugar, and
       // frankly, I don't care what you guys
       // do with it

       foreach(IAcceptSugar item in items)
          item.AddSugar();
   }
}

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

[Edit]

Возможно, я не совсем понял, поэтому поясню: если AddSugar () выполняет то же самое для группы производных объектов, вы будете Конечно, реализовать это в своем базовом классе. Но в этом примере мы сказали, что Drink не всегда должен реализовывать IAcceptSugar.

Таким образом, мы можем получить общий класс:

 public class DrinkWithSugar : Drink, IAcceptSugar { ... }

, который будет реализовывать AddSugar () таким же образом для группы напитков.

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

Мораль такова: ваша иерархия может измениться, пока ваши интерфейсы остаются прежними.

6
ответ дан 1 December 2019 в 05:55
поделиться

Две вещи, которые могут иметь значение:

1) Нил Баттерворт поднимает очень важное различие между моделью реального мира в некотором контексте и самим реальным миром. Объектно-ориентированный дизайн не зря иногда называют объектно-ориентированным моделированием. Модель касается только «интересных» аспектов реального мира. Что интересно, зависит от контекста вашего приложения.

2) Предпочитайте композицию наследованию . Напиток имеет свойства объема и температуры (которые в контексте моделирования могут быть связаны с человеческим восприятием, то есть очень холодным, холодным, теплым, горячим) и состоит из ингредиентов (воды, чая, кофе, молока, сахара, ароматизаторов). Обратите внимание, он не наследуется от ингредиентов, он сделан из них.

2
ответ дан 1 December 2019 в 05:55
поделиться

Если вы новичок, я бы не стал беспокоиться о том, что ваш шаблон дизайна не будет идеальным. Фактически многие возразят, что не существует идеального шаблона проектирования: P

Что касается вашего примера, я бы, вероятно, создал абстрактный класс для напитков, таких как чай и кофе (потому что они имеют схожие атрибуты). И попробуйте сделать так, чтобы у класса drink было очень мало атрибутов и методов. Вода и сок могут быть подклассом абстрактного класса напитков.

1
ответ дан 1 December 2019 в 05:55
поделиться

Используйте шаблон декоратора .

1
ответ дан 1 December 2019 в 05:55
поделиться

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

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

Если вам дается проблема создать классы для 4 разных виды напитков, сделать 4 разных типа без наследства. Если вам задали задачу, которая гласит: «Хорошо, теперь мы хотим дать человеку любой из этих напитков и распечатать, что он выпил», то это идеальное использование полиморфизма. Добавьте интерфейс или абстрактный базовый класс с функцией drink () . Компиляция push, обратите внимание, что все 5 классов говорят, что функция не реализована, реализуйте все 5 функций, нажмите компиляцию, и все готово.

Чтобы ответить на ваш вопрос, ваш вопрос о добавлении молока или сахара проблема, я предполагаю, что вы ' повторяется то, что вы хотите передать объект Drinkable Person , но Drinkable не содержит addMilk или ] addSugar . Эту проблему можно решить двумя или более способами, один из которых - очень плохой.

Плохой способ: передать Drinkable человеку и ввести тип осмотрите и наложите на объект, чтобы получить обратно чай или сок .

void prepare (Drinkable drink)
{
  if (drink is Juice)
  {
    Juice juice_drink = (Juick) drink;
    juice_drink.thing();
  }
}

В одну сторону:

1
ответ дан 1 December 2019 в 05:55
поделиться

Все зависит от обстоятельств - и это действительно означает - начните с самого простого дизайна и рефакторизуйте его, когда увидите в этом необходимость. Возможно, это не будет выглядеть очень блестяще ООП - но я бы начал с одного класса и свойства 'CanAddSugar' и 'SugarAmount' (позже вы могли бы обобщить его до предиката CanAddIngredient(IngredientName), чтобы люди могли добавлять виски в свои напитки :)

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

0
ответ дан 1 December 2019 в 05:55
поделиться