2015-08-16 4 views
3

Допустим, у меня есть классScala: заменить метод во время выполнения

class Original { 
    def originalMethod = 1 
} 

Теперь, скажем, у меня есть экземпляр этого

val instance = new Original 

Можно ли теперь сделать что-то instance во время выполнения заменить originalMethod другим способом? (Предоставляется подпись остается неизменным)

К примеру, в настоящее время, при вызове instance.originalMethod следующий код будет называться println("test"); 1

EDIT Я не могу назвать new Original. У меня есть только существующий экземпляр, который я должен изменить.

EDIT 2 (@Aleksey Измайлов ответ) Это хорошее решение, но это не совсем то, что я ищу. Я думаю больше о терминах тестирования - написании класса «нормально», без указания функций как переменных, а не методов

PS. Я наткнулся на этот вопрос, пытаясь имитировать шпиона Mockito.

+0

Возможно ли в вашем случае использовать агрегацию? – maks

+0

Что вы подразумеваете под агрегацией? – Andrey

ответ

1

Это не возможно на JVM - либо Java или Scala - не в том смысле, что вы просите.

См., Например, In Java, given an object, is it possible to override one of the methods?

Будучи в Scala вместо Java, вы не получаете дополнительного рычага, так как основы того, как классы и методы работают в Scala, совпадают с Java. (Это было сделано как для производительности, так и для соображений взаимодействия).

2

Похоже, вы должны вернуться к мутации, так как у вас не может быть новых экземпляров, и поведение должно измениться. Вот, пожалуй, самый простой вариант (REPL):

магазин функция как изменяемые поля:

scala> class Original { 
    | var originalMethod =() => 1 
    | } 
defined class Original 

scala> val obj = new Original 
obj: Original = [email protected] 

Это функция, которая не имеет ничего, и вам нужно позвонить apply или () на него, чтобы получить результат.

scala> obj.originalMethod 
res0:() => Int = <function0> 

scala> obj.originalMethod() 
res1: Int = 1      ^

Замените его новой функцией:

scala> obj.originalMethod =() => 2 
obj.originalMethod:() => Int = <function0> 

Теперь вы получаете новое поведение:

scala> obj.originalMethod() 
res2: Int = 2 

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

Вот общая версия этого:

scala> class Original[T] {                
    | var originalMethod:() => T = null            
    | }                     
defined class Original                 

scala> val genImpl = new Original[Int] { originalMethod =() => 111 }      
genImpl: Original[Int] = [email protected]              

scala> genImpl.originalMethod()               
res8: Int = 111                   

scala> genImpl.originalMethod =() => 222 
genImpl.originalMethod:() => Int = <function0> 

scala> genImpl.originalMethod() 
res9: Int = 222 
+0

Это приятное решение, но не совсем то, что я ищу.Я думаю больше о терминах тестирования: писать класс «нормально», не указывая функции как переменные, а не методы. – Andrey

+0

Возможно, вы могли бы использовать макросы и переписывать АСТ для того, что по сути делало бы то же самое, но скрывало подробности от пользователя , –

Смежные вопросы