Virtual types are simple:
Here is an example of virtual classes in a Java-descendent language (cclass
is a virtual class):
Features of Virtual Classes
Let's look
to another example to study the
possibilities of virtual classes. We
will use virtual classes to extend a
collaboration with a totally new
funtionality. Let’s say we have a core
data model to represent expressions:
public cclass ExprModel {
abstract public cclass Expr {}
public cclass Constant extends Expr {
protected int _val;
public Constant(int val) {
_val = val;
}
}
abstract public cclass BinaryExpr {
protected Expr _left;
protected Expr _right;
public BinaryExpr(Expr left, Expr right) {
_left = left;
_right = right;
}
}
public cclass Add extends BinaryExpr {}
public cclass Mult extends BinaryExpr {}
}
The collaboration defines Expr as the
base class for all expressions,
concrete classes to represent
constants, addition and
multiplication. Class BinaryExpr
implements the common functionality of
all expressions with two operands.
Note that the current version of
Caesar does not support constructors
with parameters and abstract methods
in cclass. The code below demonstrates
how sample expressions can be built
using such collaboration:
public model.Expr buildSampleExpr(final ExprModel model) {
model.Expr const1 = model.new Constant(-3);
model.Expr const2 = model.new Constant(2);
model.Expr op1 = model.new Mult(const1, const2);
model.Expr const3 = model.new Constant(5);
model.Expr op2 = model.new Add(op1, const3);
return op2;
}
The collaboration defines Expr as the
base class for all expressions,
concrete classes to represent
constants, addition and
multiplication. Class BinaryExpr
implements the common functionality of
all expressions with two operands.
There are a lot of different
functionality related with
expressions: their evaluation,
formatting expressions to simple text
in infix or postfix order, various
consistency checks, lookups and
transformations. We want to keep all
this specific functionality separated
from each other and from the core data
model. This can be achieved with the
help of virtual classes. For example,
the collaboration below extends the
core model with simple expression
formatting functionality:
public cclass ExprFormat extends ExprModel {
abstract public cclass Expr {
abstract public void String format();
}
public cclass Constant {
public void String format() {
return _val < 0 ? “(“ + _val + “)” : “” + _val;
}
}
abstract public cclass BinaryExpr {
public void String format() {
return “(” + _left.format() + getOperSymbol()
+ _right.format() + “)”;
}
abstract public void String getOperSymbol();
}
public cclass Add {
public void String getOperSymbol() { return “+”; }
}
public cclass Mult {
public void String getOperSymbol() { return “*”; }
}
}
This short example demonstrates
various features of virtual classes:
There is no need to repeat inheritance relationships between
virtual classes if they are already
defined in the supercollaboration. For
example ExprModel defines Constant as
subclass of Expr. It means that
Constant is implicitly assumed as
subclass of Expr in ExprFormat as
well.
Virtual classes can use the fields and methods defined in their
older versions. For example
ExprFormat.BinaryExpr can use fields
_left and _right defined in ExprModel.BinaryExpr.
The functionality defined in the overridden virtual classes can be
accessed without type casts. For
example, fields _left and _right of
BinaryExpr were initially declared
with type Expr of ExprModel, which
does not have method format(), but in
the context of ExprFormat the new
version of Expr is assumed as the type
of _left and _right. So format() can
be called without any type casts.
The methods introduced in the overridden virtual classes can be
again overridden in the new versions
of subclasses. For example overridden
Expr introduces method format(), which
can be overridden in BinaryExpr. While
Add and Mult do not override this
method further, they inherit the
format() of BinaryExpr.
Besides the demonstrated properties,
the overridden virtual classes can
also
- introduce new data fields,
- implement new interfaces,
- introduce new inheritance relationships.