Часто, когда мы разрабатываем наши программы, мы не замечаем возможных ошибок , которые вставляются в код. Дело в том, что, в некоторых случаях, поведение, наше приложение может быть очень плотно. Идея этого поста, чтобы представить этих проблем, называется escaping references , и возможные решения.
Прежде чем войти в части концептуальной, мы будем знать код, с которым мы будем работать. Проект включает в
- 1 класс, называемый
Книги
, что это представление книги
package br.com.er.model; public class Livro { public Livro(Long id, String nome, String autor, Double preco) { this.id = id; this.nome = nome; this.autor = autor; this.preco = preco; } private final Long id; private final String nome; private final String autor; private Double preco; public String getAutor() { return autor; } public void setPreco(Double preco) { this.preco = preco; } @Override public String toString() { return "Livro{" + + id + ", nome='" + nome + '\'' + ", autor='" + autor + '\'' + ", preco=" + preco + '}'; } }
- 1 класс, называемый
ColecaoDeLivros
ответственность за оказание список книг, и некоторые модели поведения, чтобы обрабатывать ее.
package br.com.er.collection; //imports omitidos public class ColecaoDeLivros { public Listlivros; public ColecaoDeLivros() { livros = List.of( new Livro(1L, "Clean Code", "Uncle Bob", 119.99) ); } public void mostrarLivros() { livros.forEach(System.out::println); } public Livro buscarPorAutor(String autor) { return livros.stream(). filter(livro -> livro.getAutor().contains(autor)) .findAny() .orElseThrow(RuntimeException::new); } }
- 1 класс
Основной
ответственность за выполнение кода.
package br.com.er; import br.com.er.collection.ColecaoDeLivros; public class Principal { public static void main(String... x) { ColecaoDeLivros cl = new ColecaoDeLivros(); cl.mostrarLivros(); System.out.println(cl.buscarPorAutor("Uncle Bob")); } }
Приведенный выше код является 100% функциональным и мы можем гарантировать это, запустив свой класс Основное
.
Intellij IDE, используемой для выполнения o код
/Library/Java/JavaVirtualMachines/jdk-11.0.9.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=50174:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/jv.martins/Documents/workspace/avoid-escaping-reference/out/production/avoid-escaping-reference br.com.er.Principal Livro{id=1, nome='Clean Code', autor='Uncle Bob', preco=119.99} Livro{id=1, nome='Clean Code', autor='Uncle Bob', preco=119.99} Process finished with exit code 0
Мы будем делать незначительные изменения в классе Основное
.
//resto do código omitido public static void main(String... x) { ColecaoDeLivros cl = new ColecaoDeLivros(); cl.mostrarLivros(); cl.buscarPorAutor("Uncle Bob").setPreco(0.0); cl.mostrarLivros(); }
Как мы можем наблюдать, метод setPreco
класса Книги
вызывается после метода buscarPorAutor
класса ColecaoDeLivros
. Это происходит потому, что возвращение buscarPorAutor
Книги
. За хорошие практики разработки, есть два варианта:
Стать невозможно вызвать метод
setPreco
.Если удается вызвать метод
setPreco
, вызов не должен оказывать влияние, например, цен на книги, возвращается не должен быть изменен.
Снова запустить проект, результат будет:
/Library/Java/JavaVirtualMachines/jdk-11.0.9.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=50116:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/jv.martins/Documents/workspace/avoid-escaping-reference/out/production/avoid-escaping-reference br.com.er.Principal Livro{id=1, nome='Clean Code', autor='Uncle Bob', preco=119.99} Livro{id=1, nome='Clean Code', autor='Uncle Bob', preco=0.0} Process finished with exit code 0
Как это не должно быть возможным, чтобы изменить цену возвращаемый объект, мы замечаем, что наше приложение не ведет себя как надо. Este é um exemplo de ускользающая ссылка . Мы меняем атрибут ” тип, через метод возвращает другой тип. В соответствии с правилами, будем модифицировать наш код, который не удается вызвать метод setPreco
.
Первым вариантом, чтобы избежать проблемы уже отмечалось, является создание интерфейса Книги
, который имеет только методы getter
package br.com.er.interfaces; public interface ILivro { String getAutor(); }
Теперь обменяем метод возвращения buscarPorAutor
интерфейс создан.
//classe ColecaoDeLivros public ILivro buscarPorAutor(String autor) { return livros.stream(). filter(livro -> livro.getAutor().contains(autor)) .findAny() .orElseThrow(RuntimeException::new); }
Это действие уже будет достаточно, чтобы код не компилируется.
Мы решаем ситуацию и теперь не удается вызвать метод setPreco
. Утвердительный предыдущее было бы совершенно верно, если бы не способ, чтобы сделать литья ILivro
для Книги
.
public static void main(String... x) { ColecaoDeLivros cl = new ColecaoDeLivros(); cl.mostrarLivros(); ILivro livro = cl.buscarPorAutor("Uncle Bob"); Livro livroConvertido = (Livro) livro; livroConvertido.setPreco(0.0); cl.mostrarLivros(); }
Мы можем заметить, что путь для вызова метода setLivro
стало труднее, но не невозможно. Приведенный выше код возвращает тот же результат, как прежде
/Library/Java/JavaVirtualMachines/jdk-11.0.9.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=49798:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/jv.martins/Documents/workspace/avoid-escaping-reference/out/production/avoid-escaping-reference br.com.er.Principal Livro{id=1, nome='Clean Code', autor='Uncle Bob', preco=119.99} Livro{id=1, nome='Clean Code', autor='Uncle Bob', preco=0.0} Process finished with exit code 0
Масса энтао нао темос ума мадейра де эвитар дефинитиваменте эссес ускользающие ссылки ? Ответ вы увидите в следующем разделе
В JPMS является feature Java, которая направлена на модуляризации JDK. Из их ряд преимуществ, один из них обеспечивает лучшую инкапсуляцию наших компонентов. В этом разделе мы будем использовать эту feature чтобы избежать проблема com экранирование ссылок .
Первый шаг-это разделить приложение на модули и определить, какие классы будут в каждом модуле. Para o nosso exemplo, vamos de finir о примерах модуло ком как классика br.com.e r.коллекция. Колекао Де Ливрос
, br.com.er.интерфейсы. Ливро
e br.com.er.модель. Ливро
. Именно структура модуля:
Вы, наверное, видели, что есть новый файл с именем module-info.java
. Этот файл необходим для компиляции приложения, и в нем можно сделать несколько настроек. Мы можем определить, какие компоненты мы хотим, чтобы были выставлены вне модуля, укрепление туннеля и приложения мы можем определить, какие модули вы хотите использовать внутри модуля, в котором мы работаем. Чтобы лучше понять, давайте проверим содержимое файла.
module avoid.escaping.reference { exports br.com.er.collection; exports br.com.er.interfaces; }
Зарезервированное слово module
служит для определения модуля, который был назван Зарезервированное слово
module служит для определения модуля, который был назван
Второй модуль будет иметь класс Основной
и будет отвечать за реализацию проекта.
Модуль выполнения зависит от модуля avoid.escaping.reference
и эта зависимость определяется в файле module-info|.
module avoid.escaping.reference.engine { requires avoid.escaping.reference; }
Важно обратить внимание на один момент. Когда мы используем export
, мы делаем экспорт пакетов (пакет в пакете), которые могут быть использованы за пределами модуля. Когда мы используем requires
мы, требуя модуль, как все, и мы будем иметь доступ ко всем ресурсам которые были экспортированы из другого модуля.
Последнее замечание: для работы приложения, – добавить в путь сборки модуля avoid.escaping.reference.engine
модуль избегать.экранирования.ссылки
.
Все настройки проведены, мы будем стараться выполнить код класса Главная
, литья проведенного в предыдущем разделе
Код показывает ошибку компиляции, потому что не экспортируем класс Книги
модуля avoid.escaping.reference
, то для модуля выполнения ( avoid.escaping.reference.engine
) этот класс не существует. Используя этот подход, мы делаем невозможное вызов метода setPreco
и достигли конечной цели.
Мы понимаем, что проблемы, упомянутые в посте, не всегда легко определить, и в этом ухудшается, потому что не каждое решение предотвращает на 100% проблему. Использование интерфейсов, в некоторых случаях отлично работает, потому что то, что мы сделали, чтобы заставить casting, не является реальностью для определенных проектов. Уже для других проектов, JPMS-это лучший вариант, потому что обеспечивает инкапсуляцию ресурсы, которые нельзя использовать за пределами модуля. Выбор будет зависеть от необходимости и конструкции. Любые вопросы, критику и предложения, я готов. До свидания!!
Ссылки на код
Оригинал: “https://dev.to/j_a_o_v_c_t_r/pt-br-evitando-escaping-references-45pb”