Перенос модели внутреннего ядра в модель вывода в Java - PullRequest
2 голосов
/ 18 ноября 2011

Здесь у меня есть некоторый код для "переноса" внутренней модели ядра в "выходную" модель для внешних плагинов.

Для этого я создаю новые экземпляры на основе конкретного подтипа переданного OldConnection и передаю (с приведением) старый экземпляр в конструктор, поэтому я могу легко поддерживать внутренние данные для методов получения и установки.

Итак, OldIncoming, OldOutgoing и OldExpected являются подтипами OldConnection.MyNewIncoming, MyNewOutgoing и MyNewExpected являются подтипами MyNewConnection.К сожалению, я не могу изменить модель внутреннего ядра, и мне нужны конкретные типы в конструкторах.

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

private MyNewConnection createIConnectedSubtypeInstance(OldConnection connection) {

    if (connection instanceof OldIncoming){
        return new MyNewIncoming((OldIncoming) connection);
    }
    if (connection instanceof OldOutgoing){
        return new MyNewOutgoing((OldOutgoing) connection);
    }
    .
    .
    .
    if (connection instanceof OldExpected){
        return new MyNewExpected((OldExpected) connection);
    }

    return new MyNewConnection(connection);
}

Ответы [ 3 ]

1 голос
/ 18 ноября 2011

Альтернативой может быть куча перегруженных методов, например:

private MyNewIncoming createIConnectedSubtypeInstance( OldIncoming connection ) {
  return new MyNewIncoming( connection );
}

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

В этом случае вы могли бы также иметь некоторое отображение OldClass-> NewClass и использовать отражение для создания экземпляров, но я сомневаюсь, что это стоило бы хлопот, если вам не нужно огромное количество отображений.

Пример:

Map<Class<? extends OldConnection>, Class<? extends NewConnection>> mapping; //initializing is up to you

public NewConnection  createIConnectedSubtypeInstance(OldConnection connection) {
  try {
    Class<? extends NewConnection> subtype = mapping.get( connection.getClass() );
    return subtype.getConstructor( connection.getClass() ).newInstance( connection );
  } catch( Exception e) { //you might want to catch the more specific types
    //handle appropriateley
  }
} 

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

Кроме того, это зависит от конструкторов новых экземпляров, которые принимают ровно один параметр типа сопоставленного класса.

1 голос
/ 18 ноября 2011

Вы можете перегрузить ваш фабричный метод:

private MyNewConnection createIConnectedSubtypeInstance(OldIncoming conn) {
   return new MyNewIncoming(conn);
}

private MyNewConnection createIConnectedSubtypeInstance(OldOutgoing conn) {
   return new MyNewOutgoing(conn);
}
...

Как указывает Томас в своем ответе, это будет работать, только если вы вызовете эти методы с правильным статическим типом:

OldIncoming a;
...
MyNewConnection b = createIConnectedSubtypeInstance(a); // will return MyNewIncoming

Поскольку перегрузка использует статическое связывание, вы не можете использовать OldConnection для a в этом случае. Если это не вариант для вас, то в какой-то момент вы застрянете при выполнении instanceof.

0 голосов
/ 18 ноября 2011

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

public MyNewConnection createNewConnectiom() {
    return MyNewConnection(this);
}

В OldIncoming переопределить с

public MyNewConnection createNewConnectiom() {
    return MyNewIncoming(this);
}

и OldExpected переопределить с помощью

public MyNewConnection createNewConnectiom() {
    return MyNewExpected(this);
}

Таким образом вы избавляетесь от ветвей и слепков.

...