Въведение в чертите в Groovy

1. Общ преглед

В този урок ще изследваме концепцията за чертите в Groovy. Те бяха представени в изданието Groovy 2.3.

2. Какво представляват чертите?

Чертите са компоненти за многократна употреба, представляващи набор от методи или поведения, които можем да използваме, за да разширим функционалността на множество класове.

Поради тази причина те се считат за интерфейси, носещи както реализации по подразбиране, така и състояние. Всички черти се дефинират с помощта на ключовата дума trait .

3. Методи

Декларирането на метод в черта е подобно на декларирането на всеки редовен метод в клас. Не можем обаче да декларираме защитени или частни методи в черта .

Нека да видим как се прилагат публични и частни методи.

3.1. Публични методи

За начало ще проучим как публичните методи се прилагат в черта.

Нека създадем черта на име UserTrait и публичен метод sayHello :

trait UserTrait { String sayHello() { return "Hello!" } }

След това ще създадем клас Employee , който реализира UserTrait :

class Employee implements UserTrait {}

Сега, нека създадем тест, за да проверим дали екземпляр на служител има достъп до метода sayHello на UserTrait :

def 'Should return msg string when using Employee.sayHello method provided by User trait' () { when: def msg = employee.sayHello() then: msg msg instanceof String assert msg == "Hello!" }

3.2. Частни методи

Също така можем да създадем частен метод в черта и да се позовем на него в друг публичен метод.

Нека видим реализацията на кода в UserTrait:

private String greetingMessage() { return 'Hello, from a private method!' } String greet() { def msg = greetingMessage() println msg return msg } 

Имайте предвид, че ако осъществим достъп до частния метод в класа на изпълнение, той ще изхвърли MissingMethodException :

def 'Should return MissingMethodException when using Employee.greetingMessage method' () { when: def exception try { employee.greetingMessage() } catch(Exception e) { exception = e } then: exception exception instanceof groovy.lang.MissingMethodException assert exception.message == "No signature of method: com.baeldung.traits.Employee.greetingMessage()" + " is applicable for argument types: () values: []" }

В черта частният метод може да бъде от съществено значение за всяко изпълнение, което не трябва да бъде заменено от който и да е клас, въпреки че се изисква от други публични методи.

3.3. Абстрактни методи

А черта може да съдържа абстрактно методи, които след това могат да бъдат приложени в друг клас:

trait UserTrait { abstract String name() String showName() { return "Hello, ${name()}!" } }
class Employee implements UserTrait { String name() { return 'Bob' } } 

3.4. Замяна на методите по подразбиране

Обикновено характеристика съдържа реализации по подразбиране на своите публични методи, но можем да ги заменим в класа на изпълнение:

trait SpeakingTrait { String speak() { return "Speaking!!" } } 
class Dog implements SpeakingTrait { String speak() { return "Bow Bow!!" } } 

Чертите не поддържат защитен и частен обхват.

4. тази ключова дума

Поведението на тази ключова дума е подобно на това в Java. Можем да разгледаме чертата като супер клас.

Например, ще създадем метод, който връща това в черта :

trait UserTrait { def self() { return this } }

5. Интерфейси

А черта може също да приложи интерфейси, точно като на редовните занимания правят.

Нека създадем интерфейс и го внедрим в черта :

interface Human { String lastName() }
trait UserTrait implements Human { String showLastName() { return "Hello, ${lastName()}!" } }

Сега, нека приложим абстрактния метод на интерфейса в класа на изпълнение:

class Employee implements UserTrait { String lastName() { return "Marley" } }

6. Свойства

Можем да добавяме свойства към черта, точно както бихме правили във всеки обикновен клас:

trait UserTrait implements Human { String email String address }

7. Разширяване на чертите

Similar to a regular Groovy class, a trait may extend another trait using the extends keyword:

trait WheelTrait { int noOfWheels } trait VehicleTrait extends WheelTrait { String showWheels() { return "Num of Wheels $noOfWheels" } } class Car implements VehicleTrait {}

We can also extend multiple traits with the implements clause:

trait AddressTrait { String residentialAddress } trait EmailTrait { String email } trait Person implements AddressTrait, EmailTrait {}

8. Multiple Inheritance Conflicts

When a class implements two or more traits that have methods with the same signature, we need to know how to resolve the conflicts. Let's look at how Groovy resolves such conflicts by default, as well as a way that we can override the default resolution.

8.1. Default Conflict Resolution

By default, the method from the last declared trait in the implements clause will be picked up.

Therefore, traits help us to implement multiple inheritances without encountering the Diamond Problem.

First, let's create two traits with a method having the same signature:

trait WalkingTrait { String basicAbility() { return "Walking!!" } } trait SpeakingTrait { String basicAbility() { return "Speaking!!" } } 

Next, let's write a class that implements both traits:

class Dog implements WalkingTrait, SpeakingTrait {} 

Because SpeakingTrait is declared last, its basicAbility method implementation would be picked up by default in the Dog class.

8.2. Explicit Conflict Resolution

Now, if we don't want to simply take the default conflict resolution provided by the language, we can override it byexplicitly choosing which method to call using the trait.super.method reference.

For instance, let's add another method with the same signature to our two traits:

String speakAndWalk() { return "Walk and speak!!" }
String speakAndWalk() { return "Speak and walk!!" }

Now, let's override the default resolution of multiple inheritance conflicts in our Dog class using the super keyword:

class Dog implements WalkingTrait, SpeakingTrait { String speakAndWalk() { WalkingTrait.super.speakAndWalk() } }

9. Implementing Traits at Runtime

To implement a trait dynamically, we can use the as keyword to coerce an object to a trait at runtime.

For instance, let’s create an AnimalTrait with the basicBehavior method:

trait AnimalTrait { String basicBehavior() { return "Animalistic!!" } }

To implement several traits at once, we can use the withTraits method instead of the as keyword:

def dog = new Dog() def dogWithTrait = dog.withTraits SpeakingTrait, WalkingTrait, AnimalTrait

10. Conclusion

In this article, we've seen how to create traits in Groovy and explored some of their useful features.

А черта е наистина ефективен начин за добавяне на общи приложения и функционалности в нашите класове. В допълнение, това ни позволява да минимизираме излишния код и улеснява поддръжката на кода.

Както обикновено, внедряването на кодове и модулните тестове за тази статия са достъпни в GitHub.