Как Вы разрабатываете класс для наследования?

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

const data = [
  {count: 400, value: "Car Wash Drops"},
  {count: 48, value: "Personal/Seeding"},
  {count: 48, value: "Personal/Seeding"},
];

let valueCounts = data.reduce((a, c) => {
  a[c.value] = a[c.value] || {current: 1, total: 0};
  a[c.value].total += 1;
  return a;
}, {});

const expected = data.map(({count, value}) => {
  if (valueCounts[value].total === 1) return [value, count];
  return [`${value} (${valueCounts[value].current++})`, count];
});

console.log(expected);

12
задан James B 4 March 2009 в 16:06
поделиться

5 ответов

Вместо того, чтобы перехешировать его слишком много, я просто отвечу, что необходимо взглянуть на проблемы, которые я имел при разделении на подклассы java.util. Свойства. Я склонен избегать многих проблем разработки для наследования путем выполнения поэтому максимально редко. Вот несколько идей проблем хотя:

  • Это - боль (или потенциально невозможный) для реализации равенства правильно, если Вы не ограничиваете его "обоими объектами, должен иметь точно тот же тип". Трудность идет с симметричным требованием это a.Equals(b) подразумевает b.Equals(a). Если a и b "10x10 квадрат" и "красный 10x10 квадрат" соответственно, затем a мог бы хорошо думать это b равно ему - и это может быть всем, что Вы на самом деле хотите протестировать на, во многих случаях. Но b знает, что это имеет цвет и a не делает...

  • Любое время, которое Вы называете виртуальным методом в своей реализации, необходимо зарегистрировать те отношения и никогда не изменять ее. Человек, происходящий из класса, должен прочитать ту документацию, также - иначе они могли бы реализовать вызов наоборот, быстро ведя к переполнению стека X вызовов Y, который звонит X, который называет Y. Это - моя основная проблема - во многих случаях необходимо зарегистрировать реализацию, которая приводит к отсутствию гибкости. Это значительно смягчено, если Вы никогда не называете один виртуальный метод от другого, но все еще необходимо зарегистрировать любые другие вызовы к виртуальным методам, даже от невиртуальных, и никогда не изменять реализацию в этом смысле.

  • Потокобезопасности трудно достигнуть даже без некоторого неизвестного кода, являющегося частью Вашего класса времени выполнения. Не только необходимо зарегистрировать модель потоков класса, но Вам, вероятно, также придется выставить блокировки (и т.д.) производным классам, таким образом, они могут быть ориентированы на многопотоковое исполнение таким же образом.

  • Рассмотрите, какая специализация допустима при оставлении в рамках контракта исходного базового класса. В каких путях методы могут быть переопределены таким образом, что вызывающая сторона не должна должна быть знать о специализации, просто что она работает? java.util. Свойства являются ярким примером плохой специализации здесь - вызывающие стороны не могут только рассматривать ее как нормальную Хеш-таблицу, потому что она должна только иметь строки для ключей и значений.

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

  • Необходимо ли реализовать своего рода способность к клонированию? Если Вы не делаете, это может мешать подклассам клонироваться правильно. Иногда клон memberwise является достаточно хорошими, но другими временами, он не может иметь смысла.

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

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

Это просто неподготовленные точки, между прочим. Я могу придумывать больше, если я думаю довольно долго. Josh Bloch помещает все это очень хорошо в Эффективный Java 2, btw.

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

Я не думаю, что когда-либо разрабатываю класс для наследования. Я просто пишу как можно меньше код, и затем когда пора скопировать и вставить для создания другого класса, я ударяю тот один метод в суперкласс (где это имеет больше смысла, чем состав). Таким образом, я позволяю Не Повторить Себя (DRY), принцип диктует мой дизайн класса.

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

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

Я думаю, что основной момент находится в предпоследнем абзаце в ответе Jon: Большинство людей думает "о разработке для наследования" с точки зрения проектирования приложений, т.е. они просто хотят, чтобы это работало, и если это не делает, это может быть зафиксировано.

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

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

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

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

Еще одна возможная проблема: То, когда Вы называете 'виртуальный' метод от конструктора в базовом классе и разделяете на подклассы, переопределяет этот метод, подкласс может использовать unitialized данные.

Код лучше:

class Base {
  Base() {
    method();
  }

  void method() {
    // subclass may override this method
  } 
}

class Sub extends Base {
  private Data data;

  Sub(Data value) {
    super();
    this.data = value;
  }

  @Override
  void method() {
    // prints null (!), when called from Base's constructor
    System.out.println(this.data);  
  }
}

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

Сводка: не называйте переопределяемые методы от конструктора

2
ответ дан 2 December 2019 в 05:04
поделиться
Другие вопросы по тегам:

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