julia_v_iluhina

Untitled

Nov 16th, 2016
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 16.85 KB | None | 0 0
  1. import static com.tasj.modularoop.core.conditions.ElementConditions.text;
  2.  
  3. public class Texts extends CollectionCondition {
  4.  
  5. ...
  6.     @Override
  7.     public List<WebElement> check(List<WebElement> entity) {
  8.     /*
  9.         не уровне AbstractCondition - назвать параметр entity - самое точное
  10.  
  11.         а тут было бы точнее - elements
  12.  
  13.         не требуется - чтобы имя параметра совпадало в методе, объявленном или реализованном в предке
  14.         и в стоде, реализованнои или перереализованном в потомке
  15.         главное - чтоб сигнатуры этого метода были одинаковы (тип возвращаемого значения, набор и типы параметров)
  16.  
  17.         просмотри все кондишены (и CollectionCondition, и ElementCondition)
  18.         подправь имя этого параметра при необходимости
  19.  
  20.         но это так, по пути красоту наводим
  21.     */
  22.    ...
  23.         for (String expectedText : expectedTexts) {
  24.             if (text(expectedText) == null) return null;
  25.             /*
  26.                 а вот такой вариант - не верный
  27.                 что есть ElementConditions.text
  28.                 это метод возвращающий кондишен
  29.                 (мы не делаем проверку, мы возвращаем объект-кондишен, который в любом случае - не равен нулл -
  30.                 посмотри на реализацию ElementConditions.text)
  31.  
  32.                 как бы ни было соблазнительно - тут не переиспользовать ElementConditions.text или его методы
  33.                 и так код получится достаточно простым
  34.                 тут не стоит выискивать - как переиспользовать ElementConditions.text
  35.  
  36.                 идеально - каждый из разработанных кондишенов  - проверять в 2-ух режимах
  37.                 когда долна проверка пройти
  38.                 и конгда должна упасть
  39.                 проверка должна себя вести предсказуемо
  40.                 и сообщение об ошибке - должно быть на
  41.             */
  42.  ************************************
  43.  public interface LazyEntity<V>
  44.     public interface Element extends LazyEntity<WebElement>
  45.         public class LazyElement implements Element
  46.  /*
  47.         развиваем и чуть подправляем структуру
  48.  
  49.         у нас - будет несколько классов - лейзи-элементов и лейзи-коллекций
  50.         все лейзи-элементы - должны будут уметь делать - один и тот же перечень действий
  51.         и аналогично - про лейзи-коллекции
  52.  
  53.         логично использовать для лейзи-элементов и лейзи-коллекций
  54.             интерфейс (потомок LazyEntity)
  55.                 тут объявляем все методы-действия
  56.             абстрактный класс
  57.                 тут реализуем все одинаковое
  58.             потомки -
  59.                 тут реализуем только то, что отличает различные классы друг от друга
  60.                     конструктор + необходимые поля
  61.                     toString
  62.                     getWrappedEntity
  63.  
  64.         эти новые интерфейсы логично назвать LazyElement & LazyCollection
  65.         абстрактные классы - AbstractLazyElement & AbstractLazyCollection
  66.         и конечные классы - будут иметь более детальные имена
  67.         (Lazy+откуда+уточнение+Element или Lazy+откуда+уточнение+Collection)
  68.         при таком нейминге - мы учитываем конвеншенсы (про это они тоже есть)
  69.         ниже дам линки
  70.  
  71.         с классами-лейзи-элементами
  72.         как у нас будут обстоять дела
  73.  
  74.         лейзи-элементы любого вида - должны уметь то - что описано в interface LazyElement
  75.         но - получать вебелемент мы будем - по-разному (фактически - реазицация getWrappedEntity)
  76.         например
  77.         мы уже реализовали - getWebDriver().findElement(locator)
  78.         а будет еще и такой вариант  - получить вебэлемент - для такого лейзи-элемента
  79.             lazyElement.find(".destroy")
  80.             lazyCollection.find(cssClass("edited"))
  81.             lazyCollection.get(3)
  82.         т е - в итоге - у нас будет несколько классов, имплементирующих interface LazyElement
  83.         причем - отличаться у них будут лишь конструкторы и  реазицация getWrappedEntity (ну и toString)
  84.         а реализация остальных методов, да и вообще набор методов - один-в-один
  85.  
  86.         вот и получим такую иерархию
  87.  
  88.          самый общий интерфейс
  89.          LazyEntity<T>
  90.  
  91.             его потомки - интерфейсы
  92.                 LazyElement
  93.                 LazyCollection
  94.  
  95.                 абстрактные классы
  96.                     AbstractLazyElement
  97.                     AbstractLazyCollection
  98.                     (реализуем все методы, кроме абстрактного getWrappedEntity,
  99.                      ну и конструктор нам тут не нужен - т к класс абстрактный)
  100.  
  101.                         набор классов - для элементов и коллекций
  102.                             наши уже разработанные варианты
  103.                                 LazyWebDriverElement
  104.                                 LazyWebDriverCollection
  105.                                 (WebDriver = откуда, см схему в нейминге - выше писала)
  106.                             список будет пополняться)
  107.  
  108.          получишь что-то такое http://joxi.ru/GrqLOX3SNZPLoA
  109.          пока закрасила те классы - которые еще у нас не появились)
  110.          ну и разумно - это в рамках core - выделить в отдельный пекедж
  111.          wrappers или entities - хорошее общее название
  112.          т к вот эти наши классы - это лишь обертка вокруг вебэлемента/списка вебэлементов
  113.  
  114.          есть конвеншенсы и по этому поводу - какие имена давать интерфейсу, какие - абстракному предку,
  115.          какие - классам-потомкам
  116.  
  117.          статья про это (лучший вариант)
  118.             http://www.vertigrated.com/blog/2011/02/interface-and-class-naming-anti-patterns-java-naming-convention-tautologies/
  119.          еще полезные линки
  120.              http://stackoverflow.com/questions/2814805/java-interfaces-implementation-naming-convention
  121.              https://web.archive.org/web/20130331071928/http://isagoksu.com/2009/development/java/naming-the-java-implementation-classes
  122.              http://programmers.stackexchange.com/questions/152759/should-i-add-an-abstract-prefix-to-my-abstract-classes
  123.  
  124.          Interfaces, abstract classes - good practice
  125.              http://stackoverflow.com/questions/1932247/abstract-classes-and-interfaces-best-practices-in-java
  126.              http://joxi.ru/E2pdR1lFB1pyM2
  127.  */
  128. ***************************
  129.  public interface Element extends LazyEntity<WebElement>{
  130. ...
  131.      Element shouldHave(Condition<WebElement> condition);
  132.      Element should(Condition<WebElement>... conditions);
  133.      /*
  134.         should, shouldHave, shouldBe - лучше реализовать как синонимы = с онинаковой сигнатурой и функциональностью
  135.         параметры (Condition<WebElement>... conditions) - обеспечат возможность работать как с одним кондишеном, так и с неколькими
  136.  
  137.         потому вариант с параметром (Condition<WebElement> condition) - не нужен
  138.  
  139.         касается и коллекции
  140.      */
  141. ******************************
  142.  
  143. public class LazyElement implements Element {
  144.  
  145.     private By locator;
  146.     public LazyElement(By locator) {
  147.     public WebElement getWrappedEntity() {
  148.     public String toString(){
  149. /*
  150.     вот это - уйдет уже к реализацию класса-потомка LazyWebDriverElement
  151.     а остальное - останется в абстрактном классе
  152.  
  153.     заметь - в австрактном классе - не конструктор не нужен
  154.     мы же не создаем объекты абстрактного класса)
  155. */
  156.     @Override
  157.     public Element clear() {
  158. /*
  159.     тут тоже надо дождаться видимости и вызвать у вебэлемента метод clear
  160. */
  161. **********************************************
  162. public class LazyCollection implements ElementCollection {
  163. ...
  164.     @Override
  165.     public Element get(int index) {
  166.     /*
  167.         крутая) - додумалась до важного)
  168.         в целом все верно, предвосхитила следующую работу)
  169.        
  170.         единственное - раз у нас уже все по полочкам
  171.         то давай тут обойдемся пока без анонимных классов
  172.         а реализуем отдельный класс LazyCollectionNthElement (тоже потомок AbstractLazyElement)
  173.         и тут - будем создавать объект вот такого типа
  174.        
  175.         тут = в классе-абстрактной коллекции
  176.         тут тоже - общую для коллекций логику - оставь в абстрактном классе
  177.        
  178.         а в потомках - будет только отличительное
  179.     */
  180. *****************************
  181.     *
  182.    
  183.         следующий наворот )
  184.    
  185.    
  186.         WebElement - это тоже интерфейс
  187.    
  188.         Если мы отнаследуем наш интерфейс LazyElement от WebElement
  189.         Это то же самое что и заявить - "наш LazyElement - полная замена WebElement - и везде где вы его использовали
  190.        вы теперь можете использовать наш лейзи враппер
  191.        который помимо всех фич вебэлемента еще и будет ждать себя..."
  192.    
  193.         конечно, можно было бы абстрактный класс реализовать имплементирующим два интерфейса
  194.         Класс может быть реализован от нескольких интерфейсов
  195.    
  196.         но тогда, при использовании переменной типа LazyElement - мы не получим функциональности WebElement
  197.    
  198.         потому тут правильнее именно отнаследовать LazyElement от WebElement
  199.    
  200.         Это в java-ООП мире достаточно прикольная практика -
  201.         всегда, когда ты хочешь сделать какие-то штуки внутри объекта публичными -
  202.         выносить их сначала в отдельный интерфейс - и потом его имплементировать
  203.    
  204.         потому что просто сделать какие-то штуки публичными - это недостаточно "строго"
  205.    
  206.         если ты четко заявляешь - мой объект поддерживает такие-то интерфейсы, тогда
  207.         все могут общаться с твоим объектом через четко прописанное API этого интерфейса
  208.    
  209.         тут надо внимательно к вопросу подойти)
  210.    
  211.         в рамках LazyElement - не реализовывай методов, одноименных с методами WebElement
  212.    
  213.         да, мы для некоторых методов потерям chainable возможности
  214.    
  215.         но зато не будет двусмысленностей
  216.    
  217.         в абстрактном классе AbstractLazyElement - реализуй все вебэлементовские методы
  218.         думаю, проблем с этим не будет
  219.    
  220.         думай - в каких методах и чего надо ждать - ничего не ждать / ждать видимости / ждать наличия в DOM
  221.        
  222.         для проверки наличия в DOM - реализуй кондишен present
  223.    
  224.     */
  225. ****************************************
  226. /*
  227.     следующий наворот )
  228.  
  229.     наворачиваем Collection )
  230.  
  231.         наследуем этот интерфейс и от Iterable<LazyElement>
  232.  
  233.         цель - уметь писать такой код
  234.  
  235.         elements = $$(...);
  236.         for(LazyElement element:elements) {
  237.             ...
  238.         }
  239.  
  240.         т е уметь обходить нашу коллекцию элементов в таком варианте цикла
  241.  
  242.         чистая теория
  243.         http://tutorials.jenkov.com/java-generics/implementing-iterable.html
  244.  
  245.         нам она практически не пригодится )
  246.         просто для понимания - разумно ознакомиться
  247.  
  248.         достаточно понять, что
  249.         при имплементировании интерфейса Iterable<...>
  250.         надо будет реализовать метод
  251.          public Iterator<ProxyElement> iterator()
  252.  
  253.         Дальше мы схитрим)
  254.  
  255.         List<...> тоже наследник Iterable<...>
  256.  
  257.         если мы внутри метода iterator()
  258.             создадим и заполним список list типа List<LazyElement> элементами из коллекции
  259.  
  260.             то тогда можно вернуть в качестве результата метода iterator() - list.iterator();
  261.  
  262.         загвоздка в том, что в коллекции  getWrappedEntity()  возвращает значение типа List<WebElement>
  263.         а мы хотим получить List<LazyElement>
  264.  
  265.         Вот и пришло время создать еще одного потомка для AbstractLazyElement
  266.           назовем его LazyWrappedWebElement (обернутый веб элемент)
  267.           будем передавать ему в конструктор вебЭлемент
  268.           как ты понимаешь, его реазизация getWrappedEntity() - будет возвращать тот же веб элемент
  269.  
  270.         И теперь опять возвращаемся к методу iterator()
  271.         Если в новый список List<LazyElement>
  272.         Ты будешь складывать новосозданные объекты типа LazyWrappedWebElement
  273.         То это будет ОК (т к LazyWrappedWebElement - потомок абстрактного класса который имплементирует интерфейс LazyElement)
  274.  
  275.         Проверяем новую функциональность на коде типа
  276.  
  277.             for (LazyElement element:tasks) {
  278.                 System.out.println(element.getText());
  279.                 element.shouldHave(text("а"));
  280.             }
  281.  
  282. */
Advertisement
Add Comment
Please, Sign In to add comment