Use an abstract class to share the unchangeable alignment flag and the rule that the reported length equals the rendered text's length. This small class inheritance hierarchy will also serve the numeric software classes in part (d). The Java interface explicitly declares
toString() so that the display contract is visible even though all Java software objects already inherit that object method.interface Data {
boolean leftJustified();
int length();
String toString();
}
abstract class AbstractData implements Data {
private final boolean leftj;
protected AbstractData(boolean leftj) { this.leftj = leftj; }
public final boolean leftJustified() { return leftj; }
public final int length() { return toString().length(); }
public abstract String toString();
}
final class StringData extends AbstractData {
private final String text;
public StringData(String s, boolean leftj) {
super(leftj);
if (s == null) throw new IllegalArgumentException("null text");
text = s;
}
public String toString() { return text; }
}There are no setters, and the stored String data type value is an immutable object, so
StringData is itself an immutable object. Its object constructor rejects a null reference instead of deferring failure until display. Consequently,An abstract data type specifies a set of abstract values and the operations on them, including their observable behavior, independently of their concrete representation. Its operation signatures say what can be requested; its laws or preconditions and postconditions say what those requests mean.
For example a stack can be specified by an empty value,
push, pop, and isEmpty, with pop(push(x,s)) returning x and leaving s. A linked list and an array can implement the same abstract data type if clients observe the same specified behavior. Encapsulation hides the representation, while a representation invariant describes which internal states are valid and an abstraction function explains which abstract value each valid internal state represents. An abstract class is a language mechanism; it is not by itself a full abstract data type specification.Two mechanisms are subtype polymorphism and parametric polymorphism.
With subtype polymorphism, a trait or abstract class declares an operation and concrete subclasses implement or override it. A
Player reference holding a House object invokes House.play through dynamic dispatch. The client is written against the common contract.With parametric polymorphism, a software class or generic method has a type parameter, such as
List[T] or def identity[T](x: T): T = x. The same definition works for many supplied type arguments, with static relationships between input and output types. Method overloading is another mechanism, usually called ad hoc polymorphism: alternatives share a name but are selected from their parameter signatures at compile time.The two writable inputs and Boolean query belong to an abstract class; each concrete logic gate overrides just that query:All three subclasses satisfy the same object interface, so the
abstract class Gate {
var inp1: Boolean = false
var inp2: Boolean = false
def evalGate: Boolean
}
class OrG extends Gate {
override def evalGate: Boolean = inp1 || inp2
}
class AndG extends Gate {
override def evalGate: Boolean = inp1 && inp2
}
class XorG extends Gate {
override def evalGate: Boolean = inp1 ^ inp2
}Gate declarations in the supplied simulator still allow access to inputs and invoke the correct Boolean function through dynamic dispatch. Boolean ^ is exclusive or; || is Boolean disjunction and && is Boolean conjunction.The program first sets both inputs of Those are the two output lines. This is a simulation of combinational logic in an order where each gate's inputs have already been calculated; the Boolean assignments copy values rather than create live wire connections.
y, so . It sets . Therefore and , givingx: true
w: false