Допустим, класс A
используется в каком-то коде, и я хочу использовать вместо него класс B
, который имеет те же методы, что и класс A
, без B
расширения A
. Что было бы проще всего сделать? Другими словами, я ищу простую, готовую к использованию и общую реализацию adaptBtoA
(она должна работать для любых двух классов, имеющих одинаковую структуру / методы). .
class A {
def foo(x: String) = "A_" + x
}
class B {
def foo(x: String) = "B_" + x
}
def bar(a: A) = {
// ...
}
bar(adaptBtoA(new B()))
Если вы знакомы с интерфейсами Go с утиной печатью, я стремлюсь к такой семантике.
ИЗМЕНИТЬ
Я думаю, что обобщенное решение может быть невозможно из-за стирания типа, хотя я не уверен. Вот моя попытка использовать библиотеку mockito
:
def adapt[F, T](impl: F): T = mock[T](new Answer[Any]() {
override def answer(inv: InvocationOnMock): Any =
classOf[T]
.getDeclaredMethod(inv.getMethod.getName, inv.getMethod.getParameterTypes:_*)
.invoke(impl, inv.getArguments:_*)
})
val a: A = adapt[B, A](new B())
val res = a.foo("test") // should be "B_test" but errors in compilation
к сожалению, это не работает, так как я получаю следующую ошибку компилятора:
type arguments [T] conform to the bounds of none of the overloaded alternatives of
value mock: [T <: AnyRef](name: String)(implicit classTag: scala.reflect.ClassTag[T])T <and> [T <: AnyRef](mockSettings: org.mockito.MockSettings)(implicit classTag: scala.reflect.ClassTag[T])T <and> [T <: AnyRef](defaultAnswer: org.mockito.stubbing.Answer[_])(implicit classTag: scala.reflect.ClassTag[T])T <and> [T <: AnyRef](implicit classTag: scala.reflect.ClassTag[T])T
Однако я могу использовать жестко запрограммированные типы для конкретных случаев использования:
def adaptBtoA(b: B): A = mock[A](new Answer[Any]() {
override def answer(inv: InvocationOnMock): Any =
classOf[B]
.getDeclaredMethod(inv.getMethod.getName, inv.getMethod.getParameterTypes:_*)
.invoke(b, inv.getArguments:_*)
})
val a: A = adaptBtoA(new B())
val res = a.foo("test") // res == "B_test"
Если получение информации о типе класса из параметра шаблона во время выполнения невозможно, возможно, я смогу использовать макросы для генерации всех adapt
функций, которые мне нужны во время компиляции? Тогда код будет выглядеть примерно так:
genAdapt[B, A]()
genAdapt[D, C]()
// etc...
Но я еще недостаточно знаю о макросах Scala, чтобы реализовать это, или если это возможно.
A
вB
или использовать магнитный шаблон Но, ИМХО, лучше всего неявные преобразования класса типов очень хрупкие. - person Luis Miguel Mejía Suárez   schedule 28.01.2020A
иB
не являются классами типов. - person solyd   schedule 28.01.2020A
, так иB
, тогда вы бы написали свою функцию в терминах класса типов, а не какого-то конкретного типа. - person Luis Miguel Mejía Suárez   schedule 28.01.2020type Closable = { def close(): Unit }
. теперь ваш код может принимать этот тип, и вы можете предоставить оба структурно эквивалентных типа (A и B). - person winson   schedule 30.01.2020