#java #scala #apache-spark
#java #scala #apache-spark
Вопрос:
У меня есть класс abstract, который расширен на 15 классов. Все 15 классов имеют общий код метода с именем exec(map: HashMap) : Unit . Поэтому я подумал о реализации этого кода в абстрактном классе. Однако этот код exec() имеет побочный эффект. Он присваивает результирующую переменную выходным данным exec(). (Я не могу изменить подпись exec, потому что она реализована из некоторого внешнего интерфейса). Вывод основан на карте, которая была передана реализующим классом.
Итак, я в замешательстве, что, если я реализую exec() в абстрактном классе, будет ли повреждено значение result vairable ?
abstract class AbstractMyClass extends externalIntefaceA{
var result : DataFrame = _
override def exec(map : HashMap): Unit{
//some logic
result = map.get(key1)
}
def eval
def getResult : DataFrame = result
}
class A1 extends AbstractMyClass{
override def eval(map : HashMap){
map.add("key1","value1")
}
}
class A2 extends AbstractMyClass{
override def eval(map : HashMap){
map.add("key1","value2")
}
}
class A3 extends AbstractMyClass{
override def eval(map : HashMap){
map.add("key1","value3")
}
}
Хорошо, не уверен, что я смог это хорошо объяснить, но будет ли результирующая переменная повреждена различными реализующими классами? Я хотел бы использовать метод exec() в абстрактном классе, потому что остальная часть кода в нем одинакова во всех 15 классах. Поэтому нет смысла переопределять ее в каждом из 15 классов и иметь локальную результирующую переменную для каждого класса. Есть ли лучшая практика для такого рода вещей?
Комментарии:
1. Какое отношение
eval()
имеет?exec()
2. eval() просто показывает, что он устанавливает некоторое значение в map, которое используется в exec() для генерации результата. Внешняя библиотека автоматически вызывает exec() каждого класса после eval()
Ответ №1:
Возможно, вы путаете классы и экземпляры. A1
и A2
т.д. — это разные классы, которые разделяют некоторую реализацию AbstractMyClass
. Но каждый раз, когда вы создаете новый объект одного из этих классов, он включает в себя новый объект типа AbstractMyClass
. Каждый объект имеет разное result
значение, поэтому вызов методов для одного объекта не повлияет на значение в другом объекте.
Однако общий дизайн здесь плохой и не функциональный. Использование var
— плохой признак, и обнародование этого var
делает невозможным узнать, кто мог изменять это значение.
Было бы лучше, если exec
бы возвращался результат, а не сохранял его, устраняя необходимость в a var
. Если новое значение требуется для последующих вычислений, то это новое значение может быть передано этим методам, а не считываться из состояния класса.
Если действительно необходимо иметь изменяемые значения, убедитесь, что они есть private
, и предоставьте методы для их изменения. И избегайте записи этих значений в основной код обработки, чтобы сохранить эту часть кода функциональной. Легче проверять и тестировать код обработки, если он не записывает никаких изменяемых значений.
Комментарии:
1. Спасибо, я думаю, что был, как уже упоминалось, я не могу изменить возвращаемое значение exec, потому что оно переопределяет другой интерфейс. Итак, я понял, что даже если я объявлю и инициализирую var result в абстрактном классе и использую его в exec() абстрактного класса, экземпляры класса все равно будут иметь свои собственные значения результирующих переменных после вызова метода exec, правильно? Было бы открыто услышать любое альтернативное дизайнерское решение.
2. Если я сделаю результат приватным в абстрактном классе, он скажет: «Абстрактный класс не может иметь модификатор private». Поэтому я инициализировал результат _ и сделал его приватным. Но я не могу переназначить его на фактическое значение в методе exec(), если я не сохраню его как var
3. Также, если я сохраняю результат как закрытый в AbstractClass, я получаю сообщение, что класс A1 должен реализовать абстрактный результат или быть объявлен абстрактным. результат var объявляется в externalIntefaceA . Я могу смело отметить, что защищен в AbstractClass без жалоб компилятора. Итак, мой абстрактный класс теперь имеет защищенный от переопределения результат var: DataFrame = _
4. Хорошо, извините, что сделать его защищенным не работает во время выполнения. В нем говорится: «переопределяющий метод приводит к черте externalInterfaceA типа => DataFrame; переменная result имеет более слабые права доступа; она должна быть общедоступной, защищенной от переопределения var result: DataFrame = _»