// classes.groovy — classes, properties, constructors, traits and @Canonical. import groovy.transform.Canonical import groovy.transform.ToString // Properties: no getters/setters to write; Groovy generates them class Customer { String name String email BigDecimal creditLimit = 5000 boolean canSpend(BigDecimal amount) { amount <= creditLimit } } def c = new Customer(name: 'Acme', email: 'ap@acme.test') // named-argument constructor println c.name // uses getName() c.creditLimit = 1000 // uses setCreditLimit() println c.canSpend(1200) // false // @Canonical: equals, hashCode, toString and constructors for free @Canonical class Line { String sku int qty BigDecimal price BigDecimal getTotal() { qty * price } } def l1 = new Line('AX-200', 24, 8.50) println l1 // Line(AX-200, 24, 8.50, 204.00) println l1.total // 204.00 println l1 == new Line('AX-200', 24, 8.50) // true // Traits: reusable behaviour you can mix into classes trait Auditable { List history = [] void audit(String event) { history << "${java.time.LocalTime.now().withNano(0)} $event".toString() } } trait Validatable { abstract List errors() boolean isValid() { errors().isEmpty() } } @ToString(includeNames = true) class Order implements Auditable, Validatable { String id List lines = [] List errors() { lines ? [] : ['order has no lines'] } } def o = new Order(id: 'PO-1') println o.valid // false (isValid() as a property) o.lines << l1 o.audit('line added') println o.valid // true println o.history.size() // 1 println o