На английском языке пара гомографов - это два слова, которые имеют одинаковое правописание, но разные значения.
В разработке программного обеспечения пара гомографических методов - это два метода с одним и тем же именем, но с разными требованиями. Посмотрим на надуманный пример, чтобы сделать вопрос максимально ясным:
interface I1 {
/** return 1 */
int f()
}
interface I2 {
/** return 2*/
int f()
}
interface I12 extends I1, I2 {}
Как я могу реализовать I12? С# имеет способ сделать это, но Java нет. Таким образом, единственный способ - это взломать. Как это можно сделать с помощью трюков reflection/bytecode/etc наиболее надежно (т.е. Это не должно быть идеальным решением, я просто хочу, чтобы тот работал лучше всего)?
Обратите внимание, что какой-то существующий массив массивных фрагментов с закрытым исходным кодом, который я не могу законно развернуть, требует параметра типа I12 и делегирует I12 как код, который имеет I1 в качестве параметра, так и код, который имеет I2 в качестве параметра. Поэтому в основном мне нужно создать экземпляр I12, который знает, когда он должен действовать как I1, и когда он должен действовать как I2, который, я считаю, может быть сделан на байт-код во время выполнения непосредственного вызывающего абонента. Мы можем предположить, что вызывающие не используют никакого отражения, потому что это простой код. Проблема в том, что автор I12 не ожидал, что Java слияния f с обоих интерфейсов, так что теперь я должен придумать лучший взломать проблему. Ничто не вызывает I12.f (очевидно, если автор написал код, который фактически называет I12.f, он бы заметил проблему перед ее продажей).
Обратите внимание, что я действительно ищу ответ на этот вопрос, а не как изменить структуру кода, который я не могу изменить. Я ищу лучшее эвристическое возможное или точное решение, если оно существует. См. "Ответ на серый" для допустимого примера (я уверен, что есть более надежные решения).
Здесь - конкретный пример того, как может возникнуть проблема гомографических методов в двух интерфейсах. И вот еще один конкретный пример:
У меня есть следующие 6 простых классов/интерфейсов. Это напоминает бизнес вокруг театра и художников, которые выступают в нем. Для простоты и быть конкретным предположим, что все они созданы разными людьми.
Set представляет собой набор, как в теории множеств:
interface Set {
/** Complements this set,
i.e: all elements in the set are removed,
and all other elements in the universe are added. */
public void complement();
/** Remove an arbitrary element from the set */
public void remove();
public boolean empty();
}
HRDepartment использует Set для представления сотрудников. Он использует сложный процесс для декодирования, который сотрудники нанимают/стреляют:
import java.util.Random;
class HRDepartment {
private Random random = new Random();
private Set employees;
public HRDepartment(Set employees) {
this.employees = employees;
}
public void doHiringAndLayingoffProcess() {
if (random.nextBoolean())
employees.complement();
else
employees.remove();
if (employees.empty())
employees.complement();
}
}
Вселенная a Set сотрудников, вероятно, будет сотрудниками, которые обратились к работодателю. Поэтому, когда на этот набор вызывается complement, все существующие сотрудники увольняются, а все остальные, которые применялись ранее, нанимаются.
Artist представляет художника, такого как музыкант или актер. У художника есть эго. Это эго может возрасти, когда другие его комплимент:
interface Artist {
/** Complements the artist. Increases ego. */
public void complement();
public int getEgo();
}
Theater выполняет операцию Artist, что, возможно, приводит к дополнению Artist. Аудитория театра может судить художника между выступлениями. Чем выше эго исполнителя, тем больше вероятность, что зрителям понравится Artist, но если эго выходит за определенную точку, художник будет восприниматься зрителями отрицательно:
import java.util.Random;
public class Theater {
private Artist artist;
private Random random = new Random();
public Theater(Artist artist) {
this.artist = artist;
}
public void perform() {
if (random.nextBoolean())
artist.complement();
}
public boolean judge() {
int ego = artist.getEgo();
if (ego > 10)
return false;
return (ego - random.nextInt(15) > 0);
}
}
ArtistSet - это просто Artist и a Set:
/** A set of associated artists, e.g: a band. */
interface ArtistSet extends Set, Artist {
}
TheaterManager запускает показ. Если зрители театра ненавидят художника, театр беседует с отделом кадров, который, в свою очередь, будет стрелять артистами, нанимать новых и т.д.:
class TheaterManager {
private Theater theater;
private HRDepartment hr;
public TheaterManager(ArtistSet artists) {
this.theater = new Theater(artists);
this.hr = new HRDepartment(artists);
}
public void runShow() {
theater.perform();
if (!theater.judge()) {
hr.doHiringAndLayingoffProcess();
}
}
}
Проблема становится понятной, когда вы пытаетесь реализовать ArtistSet: оба суперинтерфейса указывают, что complement должен делать что-то еще, поэтому вам нужно реализовать два метода complement с одной и той же сигнатурой внутри одного класса. Artist.complement является гомографом Set.complement.