Groovy support Object-Oriented Programming (OOP) and mostly is similar to Java, there are some Groovy specifics and i will mention those we go through the section. This is only going to be a quick brief over of OOP and will add to this section some of the more complex features of OOP in Groovy.
Classes, Fields and Local Variables
Groovy tries to eliminate a lot of the boilerplate code for example there are defaults for access modifiers which will be used unless you override those, also getters and setters are automatically generated if you don't specify a access modifier.
| Class example | class Person {
String firstName // default is private, plus getters and setters are created
String lastName
def dob // no type assigned (actually it's an Object)
// private | protected | public // normal Java access modifiers, but if used no getters/setters will be created
protected String f1, f2
private Date createdOn = new Date()
// static and static final same as Java
static welcomeMsg = 'HELLO STATIC'
public static final String WELCOME_MSG = 'HELLO' // you cannot change, its final, its know asa constant
// local variables
def foo() {
String msg = 'Hello' // Local variable to this method
String firstName = 'Paul'
println "$msg, $firstName"
println "$welcomemsg" // can use class variable
}
}
println Person.welcomeMsg // use static field
println Person.WELCOME_MSG // use static final field
def p1 = new Person ()
p1.foo() |
Constructors and methods again are very similar to Java, you can create contructor which can initialize a new object, you can also override. Methods can use access modifiers and return types, however you can use the def keyword to return any type.
| Constructors and Methods | @groovy.transform.ToString
class PersonM1 {
String firstName, lastName
PersonM1(String first, String last){
firstName = first
lastName = last
}
// Constructor - overrides default constructor
PersonM1(String fullName){
List parts = fullName.split(" ")
firstName = parts[0]
lastName = parts[1]
}
// methods
public void foo(String a, String b){
// do stuff
}
def foo2(String a, String b) { // def means return anything we don't care, this could replace above
}
static String doGoodWork(){ // static methods is the same as Java
println "doing good work"
}
// You can use defaults to method arguments
List someMethod(List numbers = [1,2,3], Boolean canAccessAll = false ){
}
def concat(String... args) { // use the varargs which is same in Java
println args.length
}
}
// default constructor will take parameters
PersonM1 p1 = new PersonM1("Paul", "Valle")
println p1
// default constructor breaks when you overload the constructors, so below fails
// PersonM1 p2 = new PersonM1(firstName: "Paul", lastName: "Valle")
// println p2
PersonM1 p3 = new PersonM1("Lorraine Valle")
println p3
PersonM1.doGoodWork()
PersonM1 p = new PersonM1("Paul Valle")
p.concat('a','b','c','d') |
Packages are the same as in Java, Packages are directory structures used to organize classes and interfaces, Packages provide a mechanism for software reuse, they also provide a convention for unique class names. When coding for a large project, sometimes classes can be called the same name, especially if third party developers are involved by using packages you can distinguish between class names. Normally you supply your domain name as a package location.
| Package example | package uk.co.datadisk.groovy.entities
class Person {
String firstName // default is private, plus getters and setters are created
String lastName
...
}
|
Inheritance is the same as in Java, you use the extends keywords to extend a class, you can override methods just like Java.
// Phone.groovy
@groovy.transform.ToString
class Phone {
String name
String os
String appStore
def powerOn(){
println "Power On"
}
def powerOff(){
println "Power Off"
}
def ring(){
println "Ring, Ring, Ring"
}
}
// Iphone.groovy
class Iphone extends Phone { // use the extends keyword
String iosVersion
def airPlay(){
println "Connect Air Play"
}
def powerOn(){ // override the super class powerOn() method
println "Turn on iphone"
}
}
// Groovy inheritance is same as Java
Phone iphone = new Iphone(name: "6c", appStore: "MK", os: "ios")
println iphone
iphone.powerOn()
iphone.ring()
iphone.airPlay() |
Interfaces again are the same as Java, you use the implements keyword
// IPeopleService.groovy
interface IPeopleService {
List |
Traits are reusable components representing a set of methods or behaviors that we can use to extend the functionality of multiple classes. For this reason, they're considered as interfaces, carrying both default implementations and state. All traits are defined using the trait keyword. Traits are a lot like Java 8 interfaces (default methods) but one big difference is that a trait can contain state information.
| Traits example | // FlyingAbility.groovy
trait FlyingAbility {
String fly(){ // Interface cannot have a body (unless default method), a trait can
"I'm flying" // no need for return statement in Groovy
}
abstract String foo()
private String bar() {
"bar"
}
String whoWins() {
"Flying ability wins!!!!"
}
}
// SpeakingAbility.groovy
trait SpeakingAbility {
String speak1 // a trait can hold state information
int weight = 1
private String speak2
String speak(){
"I'm speaking"
}
String whoWins() {
"Speaking ability wins!!!!"
}
}
// Bird.groovy
class Bird implements FlyingAbility, SpeakingAbility {
@Override // you can use @override annotation
String foo() {
return "foo method"
}
}
// traitsApp.groovy
Bird bird = new Bird()
println bird.fly()
println bird.speak()
println bird.foo()
//println bird.bar() // cannot use as its private
bird.speak1 = "Hello"
bird.weight = 2
println bird.speak1 + " weight: " + bird.weight
println bird.whoWins() // if have same method with same name, last trait in implements wins |
Beans in either Groovy (or Java) is more of a standard and is not a type, we use encapsulation to protect the private fields and then use getter/setters to access those private fields. Also a public no-argument constructor is created and the class implements Serializable.
| Bean example | // EmployeeBean.java
public class EmployeeBean implements Serializable {
// private properties
private String firstName;
private String lastName;
private String email;
// public no-arg constructor
public EmployeeBean() {
}
// getters & and setters
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
// toString
@Override
public String toString() {
return "EmployeeBean{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
}
// Employee.groovy // Groovy uses alot less code than Java one above
@groovy.transform.ToString
class Employee implements Serializable {
// this is the same as Java EmployeeBean file
// these are private thus getters and setters are automatically created (no access modifiers)
String firstName, lastName, email
String fullName
void setFullName(String name){
fullName = name
}
void getFullName(){
"Full Name: ${fullName}"
}
}
// DoubleBean.groovy
class DoubleBean {
public Integer value
void setValue(value){
this.value = value
}
Integer getValue(){
value * 2
}
}
// app.groovy
Employee emp = new Employee(firstName: "Paul", lastName: "Valle", email: "paul.valle@example.com")
println emp
Employee emp1 = new Employee()
emp1.firstName = "Will" // use the setter method
emp1.lastName = "Hay"
emp1.fullName = "Will Hay"
emp1.email = "will.hay@example.com"
println emp1
println emp1.fullName // use the getter method
DoubleBean db = new DoubleBean()
db.value = 100 // use the setValue method
println db.value // calling the getValue method
println db.@value // call the actual value member field (notice the @), don't use the getter
|