= Solution
Give the wrapper exclusive ownership of a fresh delegate. It maintains its own inherited size so that inherited emptiness queries remain correct:
``
class IntegerSetWithCount extends IntegerSetPattern() {
private val delegate = new IntegerSet()
private var attempts = BigInt(0)
override def contains(x: Int): Boolean = delegate.contains(x)
override def insert(x: Int): Unit = {
attempts += 1
val wasPresent = delegate.contains(x)
delegate.insert(x)
if (!wasPresent) size += 1
}
override def delete(x: Int): Unit = {
val wasPresent = delegate.contains(x)
delegate.delete(x)
if (wasPresent) size -= 1
}
override def pop(): Int = {
if (isEmpty) throw new NoSuchElementException("set is empty")
val answer = delegate.pop()
size -= 1
answer
}
override def clear: Unit = {
delegate.clear
size = 0
attempts = BigInt(0)
}
def getCount: BigInt = attempts
}
``
Use the explicit membership signature and fresh default-constructible concrete set qualified in part d. The <representation invariant> is that the wrapper's `size` equals the delegate's <cardinality> and its counter equals client insertion attempts since construction or the latest successful client clear. The updates shown preserve that invariant when delegated operations fulfill their set contracts and failure checks leave the delegate unchanged. A duplicate does not increase size; deleting an absent element does not decrease it. Size changes follow successful delegation, whereas an attempted insertion is counted immediately.
\b[<Object composition> prevents internal delegate calls from dispatching into the wrapper's counter <object methods>.] It therefore survives the particular base revision in part e. The cost is forwarding code, another <software object>, some redundant size state imposed by the chosen abstract superclass, and extra membership queries. Future <object interface> <additions> must also be forwarded explicitly. This solution is an alternative definition of the <software class> in part d, not a second simultaneous definition.
Back to article page