Несколько дней назад вышла вторая бета-версия Groovy 2.3 . Одна из главных новых возможностей Groovy 2.3 — это черты . Черта — это повторно используемый набор методов и полей, которые могут быть добавлены к одному или нескольким классам. Класс может быть составлен из нескольких признаков без использования множественного наследования (и, следовательно, избежания проблемы алмаза ).
Основное использование
Следующий фрагмент кода показывает основное определение черты в Groovy 2.3.
|
1
2
3
4
5
|
trait SwimmingAbility { def swim() { println "swimming.." }} |
Определение черты выглядит очень похоже на определение класса. Эта черта определяет единственный метод swim (). Мы можем добавить эту черту в класс, используя ключевое слово Implements:
|
1
2
3
|
class Goldfish implements SwimmingAbility { ..} |
Теперь мы можем вызывать методы swim () для объектов Goldfish:
|
1
2
|
def goldfish = new Goldfish()goldfish.swim() |
До сих пор мы могли бы достичь того же, используя наследование. Разница в том, что мы можем добавить несколько признаков к одному классу. Итак, давайте определим еще одну черту:
|
1
2
3
4
5
|
trait FlyingAbility { def fly() { println "flying.." }} |
Теперь мы можем создать новый класс, который использует обе черты:
|
1
2
3
|
class Duck implements SwimmingAbility, FlyingAbility { ..} |
Утки могут плавать и летать сейчас:
|
1
2
3
|
def duck = new Duck()duck.swim()duck.fly() |
это внутри черты
Внутри черты ключевое слово this представляет экземпляр реализации. Это означает, что вы можете написать следующее:
|
1
2
3
4
5
|
trait FlyingAbility { def fly() { println "${this.class.name} is flying.." }} |
В случае класса Duck сверху это напечатает
|
1
|
Duck is flying.. |
если мы вызываем duck.fly ().
Более сложный пример
Теперь давайте посмотрим на пример, который показывает некоторые особенности черт Groovy
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
trait Trader { int availableMoney = 0 private int tradesDone = 0 def buy(Item item) { if (item.price <= availableMoney) { availableMoney -= item.price tradesDone += 1 println "${getName()} bought ${item.name}" } } def sell(Item item) { .. } abstract String getName()} |
Как и в классах Groovy, свойства поддерживают свойства. Здесь свойство availableMoney станет частным, и будут сгенерированы публичные методы получения / установки. Эти методы могут быть доступны при реализации классов. tradesDone — это закрытая переменная, доступ к которой невозможно получить за пределами черты Trader. В рамках этой черты мы определили абстрактный метод getName (). Этот метод должен быть реализован классами, которые используют эту черту.
Давайте создадим класс, который реализует нашу черту Trader:
|
1
2
3
4
5
6
7
8
|
class Merchant implements Trader { String name String getName() { return this.name }} |
Торговец теперь может покупать предметы:
|
1
2
3
4
5
6
7
|
def bike = new Item(name: 'big red bike', price: 750)def paul = new Merchant(name: 'paul')paul.availableMoney = 2000paul.buy(bike) // prints "paul bought big red bike"println paul.availableMoney // 1250 |
Исходя из черт, переопределения и разрешения конфликтов
Черта может наследовать функциональность от другой черты, используя ключевое слово extends:
|
1
2
3
4
5
6
7
8
|
trait Dealer { def getProfit() { ... } def deal() { ... }}trait CarDealer extends Dealer { def deal() { ... }} |
Здесь черта CarDealer расширяет Dealer и переопределяет метод deal () Dealer.
Методы черты также могут быть переписаны в реализации классов:
|
1
2
3
|
class OnlineCarDealer implements CarDealer { def deal() { ... }} |
Если класс реализует более одной черты, возможно создать конфликт. Это тот случай, если две или более черты определяют метод с одинаковой сигнатурой:
|
1
2
3
4
5
6
7
8
9
|
trait Car { def drive() { ... }}trait Bike { def drive() { ... }}class DrivingThing implements Car, Bike { ... } |
В такой ситуации выигрывает последняя заявленная черта (в данном примере Bike).
Вывод
Я думаю, что черты — очень полезная концепция, и я рад видеть их в Groovy. Помимо Groovy черты mixins работают во время компиляции и поэтому могут быть доступны из кода Java. Для дальнейшего чтения я могу порекомендовать документацию Groovy 2.3 Trait .
| Ссылка: | Groovy 2.3 представляет черты нашего партнера по JCG Майкла Шаргага в блоге mscharhag, Programming and Stuff . |