Ромбовидная проблема может быть действительно решена?

Вам потребуется использовать статистический запрос вместе с функцией агрегирования строк. Фактическая функция зависит от вашей СУБД:

  • oracle: LISTAGG
  • mysql: GROUP_CONCAT
  • sql-server> = 2017: STRING_AGG
  • postgres : STRING_AGG

Вот пример для mysql:

select 
    a.detail_number,
    group_concat(
        b.tender_number
        order by b.tender_number separator ', '
    ) as tender_numbers
from 
    dbo.proposal_header b
    inner join dbo.proposal_item a 
        on a.proposal_header_id =b.id
group by a.detail_number

Использование sql-сервера < 2017:

SELECT
    pi.detail_number,
    tender_numbers = STUFF(
        (
            SELECT ',' + ph.tender_number
            FROM dbo.dbo.proposal_header AS ph
            WHERE ph.id = pi.proposal_header_id
            ORDER BY ph.tender_number
        ).value('.', 'varchar(max)'),
        1, 
        1,
        ''
    )
FROM dbo.proposal_item AS pi
GROUP BY pi.detail_number
15
задан Glorfindel 2 March 2019 в 20:03
поделиться

16 ответов

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

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

У Вас может быть ромбовидная проблема в C++ (который позволяет множественное наследование), но не в Java или в C#. Нет никакого пути к наследованию от двух классов. Реализация, которую не делают два интерфейса с тем же объявлением метода, подразумевает в этой ситуации, так как конкретная реализация метода может только быть сделана в классе.

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

Ромбовидная проблема в C++ уже решена: используйте виртуальное наследование. Или еще лучше, не будьте ленивы и наследуйтесь, когда это не будет необходимо (или неизбежно). Что касается примера Вы дали, это могло быть решено путем переопределения того, что это означает быть способным к управлению на земле или в воде. Способность переместиться через воду действительно определяют основанный на воде механизм, или просто что-то, что механизм может сделать? Я думал бы, что перемещение () функция, которую Вы описали, имеет своего рода логику позади него, которая спрашивает, "где я и я, может на самом деле переехать сюда?" Эквивалент bool canMove() функция, которая зависит от текущего состояния и свойственных способностей механизма. И Вам не нужно множественное наследование для решения той проблемы. Просто используйте смешивание, которое отвечает на вопрос по-разному в зависимости от того, что возможно и берет суперкласс в качестве шаблонного параметра, таким образом, виртуальная функция canMove будет видима через цепочку наследования.

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

Проблема действительно существует. В образце AmphibianVehicle-класс нуждаются в другой информации - поверхность. Мое предпочтительное решение состоит в том, чтобы добавить метод считывания/метод установщика на классе AmpibianVehicle для изменения поверхностного участника (перечисление). Реализация могла теперь сделать, правильная вещь и класс остаются инкапсулированными.

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

Если перемещение () имеет семантические различия на основе его являющийся Землей или Водой (а не GroundVehicle, и WaterVehicle соединяет интерфейсом с обоими самим расширяющийся интерфейс GeneralVehicle, который имеет перемещение () подпись), но ожидается, что Вы будете смешивать и соответствовать земле и водным реализаторам затем Ваш пример, каждый - действительно один из плохо разработанного API.

реальная проблема - когда коллизия имени, эффективно, случайна. например ( очень синтетический продукт):

interface Destructible
{
    void Wear();
    void Rip();
}

interface Garment
{
    void Wear();
    void Disrobe();
}

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

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

.NET имеет понятие явные интерфейсные реализации , посредством чего класс может определить два метода того же имени и подписи, пока оба отмечены к двум различным интерфейсам. Определение соответствующего метода для вызова основано на времени компиляции известный интерфейс переменной (или если отражением явным выбором вызываемого)

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

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

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

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

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

В этом случае, вероятно, было бы самым выгодным сделать, чтобы AmphibiousVehicle был подклассом Механизма (одноуровневый элемент WaterVehicle и LandVehicle), чтобы полностью избежать проблемы во-первых. Это, вероятно, было бы более корректно так или иначе, так как земноводный механизм не является водным механизмом или наземным транспортным средством, это - другая вещь в целом.

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

, Если я знаю, имеют интерфейс AmphibianVehicle, который наследовался GroundVehicle и WaterVehicle, как я реализовал бы, это - перемещение () метод?

Вы обеспечили бы реализацию, подходящую для AmphibianVehicle с.

, Если GroundVehicle перемещения "по-другому" (т.е. берет различные параметры, чем WaterVehicle), то AmphibianVehicle наследовал два различных метода, один для на воде, один для на земле. Если это не возможно, то AmphibianVehicle не должен наследоваться от GroundVehicle и WaterVehicle.

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

, Если это происходит из-за плохого дизайна класса, это - программист, который должен решить его, так как компилятор не знал бы как.

3
ответ дан 1 December 2019 в 00:18
поделиться

Нет никакой Ромбовидной проблемы с Основанным на интерфейсе наследованием.

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

С Основанным на интерфейсе наследованием существует только один implemenation метода, таким образом, нет никакой неоднозначности.

РЕДАКТИРОВАНИЕ: На самом деле то же относилось бы к Основанному на классах наследованию за методы, объявленные как Краткий обзор в суперклассе.

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

Люди Java требования не знает ромбовидной проблемы. У меня может только быть множественное наследование с интерфейсами и так как у них нет реализации, у меня нет ромбовидной проблемы. Это действительно верно?

да, потому что Вы управляете реализацией интерфейса в D. Сигнатура метода является тем же между обоими интерфейсами (B/C), и видящий, поскольку интерфейсы не имеют никакой реализации - никакие проблемы.

5
ответ дан 1 December 2019 в 00:18
поделиться

C# имеет явная интерфейсная реализация для неравнодушного контакта с этим. По крайней мере, в случае, где у Вас есть один из промежуточных интерфейсов (объект этого..)

Однако то, что, вероятно, происходит, - то, что объект AmphibianVehicle знает, является ли это в настоящее время на воде или земле, и делает правильную вещь.

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

В Вашем примере, move() принадлежит эти Vehicle интерфейс и определяет контракт, "идущий от точки для указания на B".

, Когда GroundVehicle и WaterVehicle расширяются Vehicle, они неявно наследовали этот контракт (аналогия: List.contains наследовался, его контракт от Collection.contains - воображают, указал ли он что-то другое!).

Поэтому то, когда бетон AmphibianVehicle реализации move(), контракт это действительно должно уважать, Vehicle. Существует ромб, но контракт не изменяется, рассматриваете ли Вы одну сторону ромба или другого (или я назвал бы это проблемой проектирования).

при необходимости в контракте на "перемещение" для воплощения понятия поверхности, не определяйте его в типе, который не моделирует это понятие:

public interface GroundVehicle extends Vehicle {
    void ride();
}
public interface WaterVehicle extends Vehicle {
    void sail();
}

(аналогия: get(int) контракт определяется эти List интерфейс. Это не могло возможно быть определено [1 115], поскольку наборы не обязательно заказаны)

, Или осуществите рефакторинг свой универсальный интерфейс для добавления понятия:

public interface Vehicle {
    void move(Surface s) throws UnsupportedSurfaceException;
}

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

public interface Vehicle {
    void move();
}
public interface GraphicalComponent {
    void move(); // move the graphical component on a screen
}
// Used in a graphical program to manage a fleet of vehicles:
public class Car implements Vehicle, GraphicalComponent {
    void move() {
        // ???
    }
}

, Но затем это не было бы ромбом. Больше как перевернутый треугольник.

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

Я не знаю Java, но если Интерфейсы B и C наследовались Интерфейсу A, и Интерфейсам реализаций класса D B и C, то класс D просто реализует метод перемещения однажды, и это - A.Move, который он должен реализовать. Как Вы говорите, компилятор не имеет никакой проблемы с этим.

От примера Вы даете относительно реализации AmphibianVehicle GroundVehicle и WaterVehicle, это могло легко быть решено путем хранения ссылки на Среду, например, и представления Поверхностного Свойства на Среде, которую осмотрит метод Перемещения AmphibianVehicle. Никакая потребность в этом, чтобы быть переданным в качестве параметра.

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

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

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

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

move()
{

  if (this.isOnLand())
  {
     this.moveLikeLandVehicle();
  }
  else
  {
    this.moveLikeWaterVehicle();
  }
}
1
ответ дан 1 December 2019 в 00:18
поделиться

На самом деле, если Студент и Учитель являются интерфейсами, это действительно решает вашу проблему. Если это интерфейсы, то getDepartment - это просто метод, который должен появиться в вашем классе GradTeachingFellow . Тот факт, что оба интерфейса Student и Teacher применяют этот интерфейс, вовсе не является конфликтом. Реализация getDepartment в вашем классе GradTeachingFellow обеспечит удовлетворение обоих интерфейсов без каких-либо проблем с ромбами.

НО, как указано в комментарии, это не решает проблему GradStudent , которая преподает / является TA на одном факультете и является студентом на другом. Вероятно, вам здесь нужна инкапсуляция:

public class Student {
  String getDepartment() {
    return "Economics";
  }
}

public class Teacher {
  String getDepartment() {
    return "Computer Engineering";
  }
}

public class GradStudent {
  Student learning;
  Teacher teaching;

  public String getDepartment() {
    return leraning.getDepartment()+" and "+teaching.getDepartment(); // or some such
  }

  public String getLearningDepartment() {
    return leraning.getDepartment();
  }

  public String getTeachingDepartment() {
    return teaching.getDepartment();
  }
}

Не имеет значения, что GradStudent концептуально не «имеет» учителя и ученика - инкапсуляция по-прежнему актуальна.

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

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

Классы «Студент» и «Учитель» объединяют два разных понятия «отдел», используя одно и то же имя для каждого из них. Если вы хотите использовать этот вид наследования, вам следует вместо этого определить что-то вроде «getTeachingDepartment» в Teacher и «getResearchDepartment» в Student. Ваш GradStudent, который одновременно является учителем и учеником, реализует и то, и другое.

Конечно, учитывая реалии аспирантуры, даже этой модели, вероятно, недостаточно.

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

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