Возможны ООП и полностью предотвращение наследования реализации?

Когда вы объявляете ссылочную переменную (т. е. объект), вы действительно создаете указатель на объект. Рассмотрим следующий код, в котором вы объявляете переменную примитивного типа int:

int x;
x = 10;

В этом примере переменная x является int, и Java инициализирует ее для 0. Когда вы назначаете его 10 во второй строке, ваше значение 10 записывается в ячейку памяти, на которую указывает x.

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

Integer num;
num = new Integer(10);

Первая строка объявляет переменную с именем num, но она не содержит примитивного значения. Вместо этого он содержит указатель (потому что тип Integer является ссылочным типом). Поскольку вы еще не указали, что указать на Java, он устанавливает значение null, что означает «Я ничего не указываю».

Во второй строке ключевое слово new используется для создания экземпляра (или создания ) объекту типа Integer и переменной указателя num присваивается этот объект. Теперь вы можете ссылаться на объект, используя оператор разыменования . (точка).

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

Например, вы можете имеют следующий метод:

public void doSomething(SomeObject obj) {
   //do something to obj
}

В этом случае вы не создаете объект obj, скорее предполагая, что он был создан до вызова метода doSomething. К сожалению, этот метод можно вызвать следующим образом:

doSomething(null);

В этом случае obj имеет значение null. Если метод предназначен для того, чтобы что-то сделать для переданного объекта, целесообразно бросить NullPointerException, потому что это ошибка программиста, и программисту понадобится эта информация для целей отладки.

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

/**
  * @param obj An optional foo for ____. May be null, in which case 
  *  the result will be ____.
  */
public void doSomething(SomeObject obj) {
    if(obj != null) {
       //do something
    } else {
       //do something else
    }
}

Наконец, Как определить исключение & amp; причина использования Трассировки стека

21
задан Mecki 30 April 2012 в 09:37
поделиться

8 ответов

Короткий ответ: Да это возможно. Но необходимо сделать это нарочно и не случайно (использующий финал, краткий обзор и дизайн с наследованием в памяти, и т.д.)

ответ Long:

ну, наследование не на самом деле для "повторного использования кода", это - для класса "специализация", я думаю, что это - неверное истолкование.

, Например, это очень плохая идея создать Стек из Вектора, просто потому что они подобны. Или свойства от HashTable просто, потому что они хранят значения. Посмотрите [Эффективный].

"повторное использование кода" было больше "бизнес-представлением" характеристик OO, означая, что Вы возражаете, были легко распространяемыми среди узлов; и были портативными и не не имел проблем предыдущего поколения языков программирования. Это было доказанной половиной права. У нас теперь есть библиотеки, которые могут быть легко распределены; например, в Java файлы банки могут использоваться в любом проекте, сохраняющем тысячи часов разработки. OO все еще имеет некоторые проблемы с мобильностью и подобными вещами, который является причиной теперь, WebServices так популярны (как, прежде чем это был CORBA), но это - другой поток.

Это - один аспект "повторного использования кода". Другой эффективно, тот, который имеет отношение к программированию. Но в этом случае не должен только "сохранять" строки кода и создание хрупких монстров, но и разработку с наследованием в памяти. Это - объект 17 в книге, ранее упомянутой; Объект 17: Дизайн и документ для наследования или иначе запрещают его. Видят [Эффективный]

, Конечно, у Вас могут быть Автомобильный класс и тонны подклассов. И да, подход, который Вы упоминаете об интерфейсе Car, AbstractCar и CarImplementation, является корректным способом пойти.

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

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

Наследование больше для "специализирования" классов, тем же способом Грузовик является специализированной версией Автомобиля и MosterTruck специализированная версия Грузовика.

Это не имеет смысл создать "ComputerMouse" subclase из Автомобиля просто, потому что это имеет Колесо (колесико прокрутки) как автомобиль, это перемещается и имеет колесо ниже только для сохранения строк кода. Это принадлежит другому домену, и это будет использоваться для других целей.

способ предотвратить наследование "реализации" находится на языке программирования с начала, необходимо использовать заключительное ключевое слово на объявлении класса и этом способе, которым Вы запрещаете подклассы.

Разделение на подклассы не является злым, если оно сделано нарочно. Если это сделано небрежно, это может стать кошмаром. Я сказал бы, что необходимо запустить максимально частный и "окончательный" и в случае необходимости сделать вещи больше общедоступный и растяжимый. Это также широко объяснено в представлении, "Как разработать хороший API и почему это имеет значение", Видят [Хороший API]

Продолжает читать статьи и со временем и практикой (и большое терпение), эта вещь прибудет более ясная. Хотя когда-то просто необходимо сделать работу и скопировать/вставить некоторый код: P. Это в порядке, поскольку долго Вы пытаетесь сделать это хорошо сначала.

Вот являются ссылки обоими от Joshua Bloch (раньше работающий в Sun в ядре Java, теперь работающего на Google)

<час> [Эффективный] Эффективный Java. Определенно лучшая книга a Java не новичок должна учиться, понять и практика. Необходимая вещь.

Эффективный <час> Java

[Хороший API] Представление, которое говорит на дизайне API, возможности многократного использования и связанных темах. Это немного длинно, но это ценность каждую минуту.

, Как Разработать Хороший API и Почему это Вопросы

Отношения.

<час> Обновление: Смотрите в минуту 42 из видеосвязи, которую я отправил Вам. Это говорит об этой теме:

, "Когда у Вас есть два класса в общедоступном API и Вы думаете для создания одного, подкласс другого, как Foo является подклассом Панели, спросите Ваш сам, Действительно ли каждым Foo является Панель?..."

И в минуту предыдущий это говорит о "повторном использовании кода" при разговоре о TimeTask.

11
ответ дан 29 November 2019 в 21:24
поделиться

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

В статье Вы отправили ссылку на, автор показывает "уязвимость" Стопки использования наследования и ArrayList. Пример испорчен, потому что Стек не является ArrayList, и поэтому наследование не должно использоваться. Пример столь же испорчен как Строковый Символ расширения или PointXY, расширяющий Число.

перед расширением класса необходимо всегда выполнять тест "is_a". Так как Вы не можете сказать, что Каждым Стеком является ArrayList, не будучи неправильным в некотором роде, тогда Вы не должны inheirit.

контракт для Стека отличается, чем контракт для ArrayList (или Список) и стек не должен наследовать методы, который является, не заботится о (как, добираются (интервал i) и добавляют ()). На самом деле Стек должен быть интерфейсом с методами, такими как:

interface Stack<T> {
   public void push(T object);
   public T pop();
   public void clear();
   public int size();
}

класс А как ArrayListStack мог бы реализовать интерфейс Stack и в этом случае использовать состав (имеющий внутренний ArrayList) и не наследование.

Наследование не плохо, плохое наследование плохо.

8
ответ дан 29 November 2019 в 21:24
поделиться

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

2
ответ дан 29 November 2019 в 21:24
поделиться

Вы могли также использовать состав и стратегическую модель. текст ссылки

public class Car
{
  private ICar _car;

  public void Move() {
     _car.Move();
  }
}

Это намного более гибко, чем использование основанного на наследовании поведения, поскольку это позволяет, Вы для изменения во времени выполнения, путем замены новым Автомобилем вводите как требуется.

4
ответ дан 29 November 2019 в 21:24
поделиться

Для создания mixins/composition легче смотрите на мои Аннотации и Процессор Аннотации:

http://code.google.com/p/javadude/wiki/Annotations

, В частности, mixins пример:

http://code.google.com/p/javadude/wiki/AnnotationsMixinExample

Примечание, что это в настоящее время не работает если интерфейсы/типы, делегируемые, чтобы иметь параметризованные методы (или параметризованные типы на методах). Я работаю над этим...

2
ответ дан 29 November 2019 в 21:24
поделиться

Это забавно для ответа на мой собственный вопрос, но здесь является чем-то, что я нашел, что это довольно интересно: Sather.

Это - язык программирования без наследования реализации вообще! Это знает интерфейсы (названный абстрактными классами без реализации или инкапсулировавших данных), и интерфейсы могут наследоваться друг друга (на самом деле, они даже поддерживают множественное наследование!), но класс может только реализовать интерфейсы (абстрактные классы, столько, сколько ему нравится), он не может наследоваться другому классу. Это может однако "включать" другой класс. Это - скорее понятие делегата. Включенные классы нужно инстанцировать в конструкторе Вашего класса и уничтожают, когда Ваш класс уничтожается. Если Вы не перезаписываете методы, они имеют, Ваш класс наследовал их интерфейс также, но не их код. Вместо этого методы создаются, которые просто переводят вызовы к Вашему методу к одинаково именованному методу включенного объекта. Различие между включенными объектами и просто инкапсулировавшие объекты состоят в том, что Вы не должны создавать делегацию вперед сами, и они не существуют как независимые объекты, которые можно раздать, они - часть объекта и живут и умирают вместе с объектом (или более технически говоривший: память для Вашего объекта и всех включенных создается с единственным вызовом выделения, тем же блоком памяти, Вам просто нужны к init они в Вашем вызове конструктора, в то время как при использовании настоящих делегатов, каждый из этих объектов вызывает собственный вызов выделения, имеет собственный блок памяти и живет полностью независимо от объекта).

язык не так красив, но я люблю идею позади него:-)

2
ответ дан 29 November 2019 в 21:24
поделиться

Наследование не необходимо для объектно-ориентированного языка.

Рассматривают JavaScript, который еще более объектно-ориентирован, чем Java, возможно. Нет никаких классов, просто объекты. Код снова используется путем добавления существующих методов к объекту. Объект JavaScript является по существу картой имен к функциям (и данные), где начальное содержание карты устанавливается прототипом, и новые записи могут быть добавлены к приведенному примеру на лету.

1
ответ дан 29 November 2019 в 21:24
поделиться

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

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

Шаблоны разработки Банды Четыре

0
ответ дан 29 November 2019 в 21:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: