10 steps to Object-Oriented Programming with Elan

# Getting started

To undertake object-oriented programming (OOP) with Elan, you should first be reasonably familiar with procedural programming with Elan. Start by switching to the object-oriented profile from the menu at the top of the IDE. This will still allow you to do procedural programming, but changes two things:

- The list of demo programs will now show only programs that use OOP - except that Snake is offered in both procedural and object-oriented forms for direct comparison. We will be referring to code within the OOP demo programs within this text.
- It will change some of the options available on the new code menus in the editor:
  - At the global level, it will offer: concrete class, abstract class, and interface
  - Within a concrete class, abstract class, or interface, the new code menu will show an entirely new list of instructions, collectively known as ‘members’ (plus comment) that may be defined within those three new global instructions.

In the following sections we will describe 10 principles that define the essence of OOP, illustrated with example code - where possible from the demo programs.

Important. Every textbook on OOP differs slightly in the definition of core principles, and every language that supports OOP differs in the rules that it enforces. The following 10 principles are based on widely recognised best practices in OOP. When coding with Elan, in whichever of the supported languages - Python, VB, C#, or Java (or the Elan Reference Language) - these principles are, wherever possible, enforced by the Elan tooling. The resulting code is always valid syntax for the chosen language - but may depend upon common library methods defined in the Elan library. Also, if you go on to write code in any of those languages outside Elan, you will find that the same principles are not necessarily enforced. Though that might appear to offer you more freedom, sticking voluntarily to the principles that you learned in Elan will result in better code and fewer problems.

# Principle 1: A class is a user-defined data structure type

In procedural programming with Elan, there is a fixed set of types available to you to represent data - the only exception being enums which offer a very limited form of 'user-defined' type (UDT). OOP makes it easy to define far richer forms of UDTs. The simplest and most common way to do this is to define a concrete class which is one of the new options made available at global (file) level when using Elan with the Object Oriented

profile selected.

In the Snake object-oriented demo you can find three examples of concrete classes. Only the 'signature' of each class is shown here - not the instructions contained within the classes:
+class Snake Name? inheritance?1 +constructor(parameter definitions?) 2 new code end constructor +function toString name?(parameter definitions?) returns String Type? 3 return "undefined"value or expression?4 end function end class +class Apple Name? inheritance?5 +constructor(parameter definitions?) 6 new code end constructor +function toString name?(parameter definitions?) returns String Type? 7 return "undefined"value or expression?8 end function end class +class Square Name? inheritance?9 +constructor(parameter definitions?) 10 new code end constructor +function toString name?(parameter definitions?) returns String Type? 11 return "undefined"value or expression?12 end function end class
+class Snake Name? inheritance? # concrete class 1 +def __init__(self: Snake) -> None: 2 new code +def toString name?(self: Snake) -> str Type?: # function method 3 return "undefined"value or expression?4 +class Apple Name? inheritance? # concrete class 5 +def __init__(self: Apple) -> None: 6 new code +def toString name?(self: Apple) -> str Type?: # function method 7 return "undefined"value or expression?8 +class Square Name? inheritance? # concrete class 9 +def __init__(self: Square) -> None: 10 new code +def toString name?(self: Square) -> str Type?: # function method 11 return "undefined"value or expression?12
+class Snake Name? inheritance? {1 +public Snake(parameter definitions?) { 2 new code } // constructor +public string Type? toString name?(parameter definitions?) { // function method 3 return "undefined"value or expression?;4 } // function method } // class +class Apple Name? inheritance? {5 +public Apple(parameter definitions?) { 6 new code } // constructor +public string Type? toString name?(parameter definitions?) { // function method 7 return "undefined"value or expression?;8 } // function method } // class +class Square Name? inheritance? {9 +public Square(parameter definitions?) { 10 new code } // constructor +public string Type? toString name?(parameter definitions?) { // function method 11 return "undefined"value or expression?;12 } // function method } // class
+Class Snake Name? inheritance? inheritance?1 +Sub New(parameter definitions?) 2 new code End Sub +Function toString name?(parameter definitions?) As String Type? 3 Return "undefined"value or expression?4 End Function End Class +Class Apple Name? inheritance? inheritance?5 +Sub New(parameter definitions?) 6 new code End Sub +Function toString name?(parameter definitions?) As String Type? 7 Return "undefined"value or expression?8 End Function End Class +Class Square Name? inheritance? inheritance?9 +Sub New(parameter definitions?) 10 new code End Sub +Function toString name?(parameter definitions?) As String Type? 11 Return "undefined"value or expression?12 End Function End Class
+class Snake Name? inheritance? inheritance? {1 +public Snake(parameter definitions?) { 2 new code } // constructor +public String Type? toString name?(parameter definitions?) { // function method 3 return "undefined"value or expression?;4 } // function method } // class +class Apple Name? inheritance? inheritance? {5 +public Apple(parameter definitions?) { 6 new code } // constructor +public String Type? toString name?(parameter definitions?) { // function method 7 return "undefined"value or expression?;8 } // function method } // class +class Square Name? inheritance? inheritance? {9 +public Square(parameter definitions?) { 10 new code } // constructor +public String Type? toString name?(parameter definitions?) { // function method 11 return "undefined"value or expression?;12 } // function method } // class

Within the definition of each class you will find several property instructions. Each property has unique name (within the class). A class may defined multiple properties of the same type, for example, the `SquareSquareSquareSquareSquare` class in Snake defines:

+constructor(parameter definitions?) 0 new code end constructor
property x as Int Code does not parse as Elan.
property x as Int Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property x as Int Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property y as Int Code does not parse as Elan.
property y as Int Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property y as Int Code does not parse as Elan.
or properties may have different types, for example the `TuringMachineTuringMachineTuringMachineTuringMachineTuringMachine` class in the Roman Numerals Turing Machine demo has these:- the class may have multiple properties of the same type but with different names, or define
+constructor(parameter definitions?) 0 new code end constructor
property initialState as String Code does not parse as Elan.
property initialState as String Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property initialState as String Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property currentState as String Code does not parse as Elan.
property currentState as String Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property currentState as String Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property headPosition as Int Code does not parse as Elan.
property headPosition as Int Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property headPosition as Int Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property haltState as String Code does not parse as Elan.
property haltState as String Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property haltState as String Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property rules as List Code does not parse as Elan.
property rules as List Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property rules as List Code does not parse as Elan.
+constructor(parameter definitions?) 0 new code end constructor
property tape as String Code does not parse as Elan.
property tape as String Code does not parse as Elan.
+Sub New(parameter definitions?) 0 new code End Sub
property tape as String Code does not parse as Elan.

### Defining a class

Selecting concrete class from the new code menu inserts a template like this:

+class Name Name? inheritance?1 +constructor(parameter definitions parameter definitions?) 2 new code end constructor +function toString name?(parameter definitions parameter definitions?) returns String Type? 3 return "undefined"value or expression?4 end function end class
+class Name Name? inheritance? # concrete class 1 +def __init__(self: Name) -> None: 2 new code +def toString name?(self: Name) -> str Type?: # function method 3 return "undefined"value or expression?4
+class Name Name? inheritance? {1 +public Name(parameter definitions parameter definitions?) { 2 new code } // constructor +public string Type? toString name?(parameter definitions parameter definitions?) { // function method 3 return "undefined"value or expression?;4 } // function method } // class
+Class Name Name? inheritance? inheritance?1 +Sub New(parameter definitions parameter definitions?) 2 new code End Sub +Function toString name?(parameter definitions parameter definitions?) As String Type? 3 Return "undefined"value or expression?4 End Function End Class
+class Name Name? inheritance? inheritance? {1 +public Name(parameter definitions parameter definitions?) { 2 new code } // constructor +public String Type? toString name?(parameter definitions parameter definitions?) { // function method 3 return "undefined"value or expression?;4 } // function method } // class
where the only thing you must provide is a unique name for the class, which must start with a capital letter, followed by other letters, digits or underscores. (We will look at the roles of the constructor, and the toString function later on.)

# Principle 2: An object is an instance of a class

Every object in code is an instance of a specific class. The class may be thought of as a 'template' for defining instances. Each instance holds its own specific value for each of the properties defined in the class.

An new object may be created and assigned to a variable definition, for example:

variable apple name? set to new Apple()value or expression?0
apple name? = Apple()value or expression? # variable definition 0
var apple name? = new Apple()value or expression?;0
Dim apple name? = New Apple()value or expression? ' variable definition 0
var apple name? = new Apple()value or expression?;0
variable snake name? set to new Snake()value or expression?0
snake name? = Snake()value or expression? # variable definition 0
var snake name? = new Snake()value or expression?;0
Dim snake name? = New Snake()value or expression? ' variable definition 0
var snake name? = new Snake()value or expression?;0

Note that the type of each variable is determined by the class of the instance so that the `appleappleappleappleapple` variable may subsequently be reassigned to a different instance of `AppleAppleAppleAppleApple` but may not be reassigned to an instance of a different class (nor any other type).

A new instance may also be created as part of an expression without having to be assigned to a variable, for example:

return new Square(newX, newY) Code does not parse as Elan.
return new Square(newX, newY) Code does not parse as Elan.
return new Square(newX, newY) Code does not parse as Elan.
return new Square(newX, newY) Code does not parse as Elan.
return new Square(newX, newY) Code does not parse as Elan.

### Reading properties

Wherever you have a reference to an object, your code may read and make use of the publicly-visible properties of that object using 'dot syntax', for example (from the Pathfinder demo):

+if distViaCurrent < neighbour.distFromStart condition? then 0 new code end if
+if distViaCurrent < neighbour.distFromStart condition?: 0 new code
+if (distViaCurrent < neighbour.distFromStart condition?) { 0 new code } // if
+If distViaCurrent < neighbour.distFromStart condition? Then 0 new code End If
+if (distViaCurrent < neighbour.distFromStart condition?) { 0 new code } // if
is comparing the value of the variable `distViaCurrentdistViaCurrentdistViaCurrentdistViaCurrentdistViaCurrent` to the property named `distFromStartdistFromStartdistFromStartdistFromStartdistFromStart` of the object named `neighbourneighbourneighbourneighbourneighbour`.

# Principle 3: The constructor initialises the properties

When coding with Elan every class must define a constructor, the template for which is created when you define a new class, and which may be edited, though not deleted. The role of the constructor is to initialise the properties whenever an instance of that class is created.

The only properties that don't need to be initialised are properties of type `IntintintIntegerint`, `FloatfloatdoubleDoubledouble`, or `BooleanboolboolBooleanbool` - which are automatically initialised to the default value of each type - `00000`, `0.00.00.00.00.0`, or `falseFalsefalseFalsefalse` respectively. All other properties must be explicitly initialised within the constructor. Here is simple example of properties being initialised within the constructor for `SquareSquareSquareSquareSquare` in the Snake demo:

constructor(x as Int, y as Int) reassign this.x to x reassign this.y to y end constructor Code does not parse as Elan.
constructor(x as Int, y as Int) reassign this.x to x reassign this.y to y end constructor Code does not parse as Elan.
constructor(x as Int, y as Int) reassign this.x to x reassign this.y to y end constructor Code does not parse as Elan.
constructor(x as Int, y as Int) reassign this.x to x reassign this.y to y end constructor Code does not parse as Elan.
constructor(x as Int, y as Int) reassign this.x to x reassign this.y to y end constructor Code does not parse as Elan.

### Note:

- Even properties that are automatically initialised may be explicitly initialised in the constructor.
- It is quite common to initialise strings to an empty string - `""""""""""` and a list to any empty list of the appropriate member-type, for example `new List Code does not parse as Elan.new List Code does not parse as Elan.new List Code does not parse as Elan.new List Code does not parse as Elan.new List Code does not parse as Elan.` - though you may choose any value.
- If you don't you want every instance of a class to be initialised with the same value, the specific value for an instance is specified via paramaters added into the constructor definition.
- When a new instance is created, arguments for each parameter must be specified (as they would be for a procedure or function), so creating a new `SquareSquareSquareSquareSquare` for example takes the form `variable tailname? set to new Square(20, 15)value or expression?0tailname? = Square(20, 15)value or expression? # variable definition0var tailname? = new Square(20, 15)value or expression?;0Dim tailname? = New Square(20, 15)value or expression? ' variable definition0var tailname? = new Square(20, 15)value or expression?;0`
- A property is initialised within the construction using a reassign variable instruction - since a property may be thought of as a named variable that holds a value specific to each instance of the class.
- the name of the property being reassigned must be prefixed by this self Me this Me followed by a dot.

# Principle 4: Objects may have associations to other objects

So far we have looked at properties where the type is one of the standard library types. However, a class may define one or more properties where the type is a class - either of the same type as the class in which the property is defined, or - more commonly - of a different class. Each such property is referred to as an 'association' or 'associated object'. If the type of a property is a list, or other data structure, where the member type is a class, then it is often referred to as a 'multiple association' - with the ordinary kind of association referred to as 'single association'. The `SnakeSnakeSnakeSnakeSnake` class shows both kinds of association (only relevant parts of the class are shown only here):

+class Snake Name? inheritance?1 +constructor(parameter definitions parameter definitions?) 2 variable tail name? set to new Square(20, 15)value or expression?3 reassign this.currentDir variableName? to Direction.right value or expression?4 reassign this.body variableName? to [tail]value or expression?5 reassign this.head variableName? to tail.getAdjacentSquare(this.currentDir)value or expression?6 reassign this.priorTail variableName? to tail value or expression?7 end constructor private property currentDir name? as Direction Type?8 private property head name? as Square Type?9 private property body name? as List<of Square>Type?10 private property priorTail name? as Square Type?11 +function toString name?(parameter definitions?) returns String Type? 12 return "undefined"value or expression?13 end function end class
+class Snake Name? inheritance? # concrete class 1 +def __init__(self: Snake) -> None: 2 tail name? = Square(20, 15)value or expression? # variable definition 3 self.currentDir variableName? = Direction.right value or expression? # reassign variable 4 self.body variableName? = [tail]value or expression? # reassign variable 5 self.head variableName? = tail.getAdjacentSquare(self.currentDir)value or expression? # reassign variable 6 self.priorTail variableName? = tail value or expression? # reassign variable 7 currentDir name?: Direction Type? # private property 8 head name?: Square Type? # private property 9 body name?: list[Square]Type? # private property 10 priorTail name?: Square Type? # private property 11 +def toString name?(self: Snake) -> str Type?: # function method 12 return "undefined"value or expression?13
+class Snake Name? inheritance? {1 +public Snake(parameter definitions parameter definitions?) { 2 var tail name? = new Square(20, 15)value or expression?;3 this.currentDir variableName? = Direction.right value or expression?; // reassign variable 4 this.body variableName? = [tail]value or expression?; // reassign variable 5 this.head variableName? = tail.getAdjacentSquare(this.currentDir)value or expression?; // reassign variable 6 this.priorTail variableName? = tail value or expression?; // reassign variable 7 } // constructor private Direction Type? currentDir name? {get; private set;} // private property 8 private Square Type? head name? {get; private set;} // private property 9 private List<Square>Type? body name? {get; private set;} // private property 10 private Square Type? priorTail name? {get; private set;} // private property 11 +public string Type? toString name?(parameter definitions?) { // function method 12 return "undefined"value or expression?;13 } // function method } // class
+Class Snake Name? inheritance? inheritance?1 +Sub New(parameter definitions parameter definitions?) 2 Dim tail name? = New Square(20, 15)value or expression? ' variable definition 3 Me.currentDir variableName? = Direction.right value or expression? ' reassign variable 4 Me.body variableName? = {tail}value or expression? ' reassign variable 5 Me.head variableName? = tail.getAdjacentSquare(Me.currentDir)value or expression? ' reassign variable 6 Me.priorTail variableName? = tail value or expression? ' reassign variable 7 End Sub Private Property currentDir name? As Direction Type?8 Private Property head name? As Square Type?9 Private Property body name? As List(Of Square)Type?10 Private Property priorTail name? As Square Type?11 +Function toString name?(parameter definitions?) As String Type? 12 Return "undefined"value or expression?13 End Function End Class
+class Snake Name? inheritance? inheritance? {1 +public Snake(parameter definitions parameter definitions?) { 2 var tail name? = new Square(20, 15)value or expression?;3 this.currentDir variableName? = Direction.right value or expression?; // reassign variable 4 this.body variableName? = [tail]value or expression?; // reassign variable 5 this.head variableName? = tail.getAdjacentSquare(this.currentDir)value or expression?; // reassign variable 6 this.priorTail variableName? = tail value or expression?; // reassign variable 7 } // constructor private Direction Type? currentDir name?; // private property 8 private Square Type? head name?; // private property 9 private List<Square>Type? body name?; // private property 10 private Square Type? priorTail name?; // private property 11 +public String Type? toString name?(parameter definitions?) { // function method 12 return "undefined"value or expression?;13 } // function method } // class

### Note:

- The`SnakeSnakeSnakeSnakeSnake` is always initialised to the same values, so the constructor does not need to define any parameters.
- The `currentDircurrentDircurrentDircurrentDircurrentDir` property is of type `DirectionDirectionDirectionDirectionDirection` (which is an enum) and is initialised to `Direction.rightDirection.rightDirection.rightDirection.rightDirection.right`.
- The `bodybodybodybodybody` property is a multiple association - defined as a list of type `Square`
- The constructor defines a variable `tail Code does not parse as Elan.Square`
- The constructor defines a variable `tail Code does not parse as Elan.Square`
- The constructor defines a variable `tail Code does not parse as Elan.Square`
- The constructor defines a variable `tail Code does not parse as Elan.Square`
- The constructor defines a variable `tail Code does not parse as Elan.` used only for the purpose of initialising properties. It is first used to initialise the `bodybodybodybodybody` as a list containing only the `tailtailtailtailtail` and is finally used to define the `priorTailpriorTailpriorTailpriorTailpriorTail` which is a single association of type `SquareSquareSquareSquareSquare`. In between it is used in an expression to determine the initial value for the `headheadheadheadhead` property using a function (more on this in the next heading).
- It is thus legitimate to call functions within the constructor. A constructor may not call any procedure, however. And you should avoid doing any work in a constructor other than determining appropriate values for initialising its properties.

# Principle 5: Classes provide behaviour through methods

#

In the last code example `tail.getAdjacentSquare(this.currentDir)tail.getAdjacentSquare(self.currentDir)tail.getAdjacentSquare(this.currentDir)tail.getAdjacentSquare(Me.currentDir)tail.getAdjacentSquare(this.currentDir)` was calling a function method, using 'dot syntax' on the the variable `tailtailtailtailtail` which is an instance of class `SquareSquareSquareSquareSquare`. A class can define both function methods and procedure methods, for the following reasons:

- these methods are invoked on an instance using 'dot-syntax' as we shown in the previous example
- they have access to all the properties belonging to that same instance, and they can also invoke other methods on the same object, prefixed by this self Me this Me dot.

This may be seen in the implementation of getAdjacentSquare in the `SquareSquareSquareSquareSquare` class:

+function getAdjacentSquare name?(d as Direction parameter definitions?) returns Square Type? 1 variable newX name? set to this.x value or expression?2 variable newY name? set to this.y value or expression?3 +if d is Direction.left condition? then 4 reassign newX variableName? to this.x - 1 value or expression?5 elif d is Direction.right condition? then 6 reassign newX variableName? to this.x + 1 value or expression?7 elif d is Direction.up condition? then 8 reassign newY variableName? to this.y - 1 value or expression?9 elif d is Direction.down condition? then 10 reassign newY variableName? to this.y + 1 value or expression?11 end if return new Square(newX, newY)value or expression?12 end function
+def getAdjacentSquare name?(d: Direction parameter definitions?) -> Square Type?: # function 1 newX name? = self.x value or expression? # variable definition 2 newY name? = self.y value or expression? # variable definition 3 +if d == Direction.left condition?: 4 newX variableName? = self.x - 1 value or expression? # reassign variable 5 elif d == Direction.right condition?: # else if 6 newX variableName? = self.x + 1 value or expression? # reassign variable 7 elif d == Direction.up condition?: # else if 8 newY variableName? = self.y - 1 value or expression? # reassign variable 9 elif d == Direction.down condition?: # else if 10 newY variableName? = self.y + 1 value or expression? # reassign variable 11 return Square(newX, newY)value or expression?12
+static Square Type? getAdjacentSquare name?(Direction d parameter definitions?) { // function 1 var newX name? = this.x value or expression?;2 var newY name? = this.y value or expression?;3 +if (d == Direction.left condition?) { 4 newX variableName? = this.x - 1 value or expression?; // reassign variable 5 } else if (d == Direction.right condition?) {6 newX variableName? = this.x + 1 value or expression?; // reassign variable 7 } else if (d == Direction.up condition?) {8 newY variableName? = this.y - 1 value or expression?; // reassign variable 9 } else if (d == Direction.down condition?) {10 newY variableName? = this.y + 1 value or expression?; // reassign variable 11 } // if return new Square(newX, newY)value or expression?;12 } // function
+Function getAdjacentSquare name?(d As Direction parameter definitions?) As Square Type? 1 Dim newX name? = Me.x value or expression? ' variable definition 2 Dim newY name? = Me.y value or expression? ' variable definition 3 +If d = Direction.left condition? Then 4 newX variableName? = Me.x - 1 value or expression? ' reassign variable 5 ElseIf d = Direction.right condition? Then 6 newX variableName? = Me.x + 1 value or expression? ' reassign variable 7 ElseIf d = Direction.up condition? Then 8 newY variableName? = Me.y - 1 value or expression? ' reassign variable 9 ElseIf d = Direction.down condition? Then 10 newY variableName? = Me.y + 1 value or expression? ' reassign variable 11 End If Return New Square(newX, newY)value or expression?12 End Function
+static Square Type? getAdjacentSquare name?(Direction d parameter definitions?) { // function 1 var newX name? = this.x value or expression?;2 var newY name? = this.y value or expression?;3 +if (d == Direction.left condition?) { 4 newX variableName? = this.x - 1 value or expression?; // reassign variable 5 } else if (d == Direction.right condition?) {6 newX variableName? = this.x + 1 value or expression?; // reassign variable 7 } else if (d == Direction.up condition?) {8 newY variableName? = this.y - 1 value or expression?; // reassign variable 9 } else if (d == Direction.down condition?) {10 newY variableName? = this.y + 1 value or expression?; // reassign variable 11 } // if return new Square(newX, newY)value or expression?;12 } // function

Function and procedure methods defined on a class have similaries and differences to global functions and procedures.

TO STRING

## Function method

Where properties define state, methods define behaviour Function & procedure methods – distinction (like globals) & commonality – optional params EXAMPLES Invoked on an instance using dot syntax EXAMPLES Implementation of methods Why put behaviour onto methods? The toString method

## Procedure method

# Principle 6: Object represent identifiable concepts in the application domain

This is encapsulation meaning 1 It is never a complete representation, but it is complete for the purposes of the application Most of the objects It not only represents its state, but its behaviour. By making objects the fundamental building blocks of programs they are easier to change and extend

# Principle 7: Objects should hide state behind methods, where possible

Does not mean getter and setter methods This is encapsulation meaning 2 Private properties, public methods – why and how Can make methods private too – where they are called by other methods in the same class.

# Principle 8: Allow objects of different classes to be handled through a common interface May be handled through interfaces or inheritance Where appropriate it is possible to deal with instances or two or more separate classes without having to know which type each one is A class can implement multiple interfaces, as long as they don’t clash An interface cannot be instantiated – but a concrete class that implements that interface can be An interface may extend another interface Each class that implements an interface must provide an implemented of each method, but the implementation may differ (EXAMPLES). It is likely that more than one class might have exactly the same implementation, and by the DRY principle it is undesirable to repeat the code. So you delegate, in part or in whole

# Principle 9: Common implementations may be shared through delegation or inheritance

An abstract class … An abstract class is like an interface, but more powerful that it may also define concrete implementations of methods, with some limitations The limitation is that a concrete class may (optionally) inherit only from one abstract class – though it may implement additional interfaces An abstract class may inherit from another abstract class and/or implement interfaces Elan’s model of inheritance – what you can and can’t do -

# Principle 10: Application logic should be well-distributed across classes

As much as possible of the code should be defined in classes With a minimal main and/or standalone (global) constructs The logic should be distributed as evenly as possible across the classes Be wary of singletons In particular of a singleton that is doing most of the work. This pattern is often used to avoid global variables, but be wary of this