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 |