class Knob(door: Door) {
private var latched: Boolean = true
def is_latched_off = !latched
def turn = latched = false
def unturn = if (door.is_close) latched = true
}
class Door {
var knob: Knob = new Knob(this)
private var closed: Boolean = true
def is_close = closed
def is_open = !is_close
def can_be_open = is_open || knob.is_latched_off
def be_open = if (can_be_open) closed = false
def be_close = { closed = true; knob.unturn }
def push = be_open
def pull = be_close
}
class DoorCloserPull(door: DoorWithCloser) extends Thread {
var done: Boolean = false
override def run = {
Thread.sleep(door.delay)
if (!done) door.pull
}
}
class DoorWithCloser extends Door {
var delay = 300
var delayed_pull = new DoorCloserPull(this)
override def push = {
super[Door].push
if (!delayed_pull.done) delayed_pull.done = true
delayed_pull = new DoorCloserPull(this)
delayed_pull.start
}
}
trait AbstractDoorStopper {
var stoppered: Boolean
def pull: Unit
def push: Unit
}
trait DoorStopper extends AbstractDoorStopper {
def be_stoppered_on = stoppered = true
def be_stoppered_off = stoppered = false
abstract override def pull = if (!stoppered) super.pull
abstract override def push = { be_stoppered_off; super.push }
}
class DoorWithStopper extends Door with DoorStopper {
var stoppered = false
override def pull = super.pull
override def push = super.push
}
class DoorWithCloserStopper extends DoorWithCloser with DoorStopper {
var stoppered = false
override def be_stoppered_off = push
override def pull = super.pull
override def push = {
super[DoorStopper].be_stoppered_off
super[DoorWithCloser].push
}
}
object Main extends App {
var door = new Door
println("door is a Door...")
door.knob.turn
println("door.knob.turn; door.can_be_open => " + door.can_be_open)
door.knob.unturn
println("door.knob.unturn; door.can_be_open => " + door.can_be_open)
door.push
println("door.push; door.is_open => " + door.is_open)
door.knob.turn; door.push
println("door.knob.turn; door.push; door.is_open => " + door.is_open)
door.pull
println("door.pull; door.is_close => " + door.is_close)
println("door.can_be_open => " + door.can_be_open + "\n")
var door2 = new DoorWithCloser
println("door2 is a DoorWithCloser...")
door2.knob.turn; door2.push
println("door2.knob.turn; door2.push; door2.is_open => " + door2.is_open)
print("0.1 second after")
Thread.sleep(100)
println(", door2.is_open => " + door2.is_open)
print("0.4 seconds after")
Thread.sleep(300)
println(", door2.is_open => " + door2.is_open + "\n")
var door3 = new DoorWithStopper
println("door3 is a DoorWithStopper...")
door3.knob.turn; door3.push
println("door3.knob.turn; door3.push; door3.is_open => " + door3.is_open)
door3.be_stoppered_on; door3.pull
println("door3.be_stoppered_on; door3.pull; door3.is_close => " + door3.is_close)
door3.be_stoppered_off; door3.pull
println("door3.be_stoppered_off; door3.pull; door3.is_close => " + door3.is_close)
door3.knob.turn; door3.push
println("door3.knob.turn; door3.push; door3.is_open => " + door3.is_open)
door3.be_stoppered_on; door3.pull
println("door3.be_stoppered_on; door3.pull; door3.is_close => " + door3.is_close)
door3.push; door3.pull
println("door3.push; door3.pull; door3.is_close => " + door3.is_close + "\n")
var door4 = new DoorWithCloserStopper
println("door4 is a DoorWithCloserStopper...")
door4.knob.turn; door4.push
println("door4.knob.turn; door4.push; door4.is_open => " + door4.is_open)
door4.be_stoppered_on
print("door4.be_stoppered_on; 0.4 seconds after")
Thread.sleep(400)
println(", door4.is_open => " + door4.is_open)
door4.be_stoppered_off
print("door4.be_stoppered_off; 0.4 seconds after")
Thread.sleep(400)
println(", door4.is_open => " + door4.is_open)
door4.knob.turn; door4.push
println("door4.knob.turn; door4.push; door4.is_open => " + door4.is_open)
door4.be_stoppered_on
print("door4.be_stoppered_on; 0.4 seconds after")
Thread.sleep(400)
println(", door4.is_open => " + door4.is_open)
door4.push
print("door4.push; 0.4 seconds after")
Thread.sleep(400)
println(", door4.is_open => " + door4.is_open + "\n")
}
Y2xhc3MgS25vYihkb29yOiBEb29yKSB7Cglwcml2YXRlIHZhciBsYXRjaGVkOiBCb29sZWFuID0gdHJ1ZQoJZGVmIGlzX2xhdGNoZWRfb2ZmID0gIWxhdGNoZWQKCWRlZiB0dXJuID0gbGF0Y2hlZCA9IGZhbHNlCglkZWYgdW50dXJuID0gaWYgKGRvb3IuaXNfY2xvc2UpIGxhdGNoZWQgPSB0cnVlCn0KCmNsYXNzIERvb3IgewoJdmFyIGtub2I6IEtub2IgPSBuZXcgS25vYih0aGlzKQoJcHJpdmF0ZSB2YXIgY2xvc2VkOiBCb29sZWFuID0gdHJ1ZQoJZGVmIGlzX2Nsb3NlID0gY2xvc2VkCglkZWYgaXNfb3BlbiA9ICFpc19jbG9zZQoJZGVmIGNhbl9iZV9vcGVuID0gaXNfb3BlbiB8fCBrbm9iLmlzX2xhdGNoZWRfb2ZmCglkZWYgYmVfb3BlbiA9IGlmIChjYW5fYmVfb3BlbikgY2xvc2VkID0gZmFsc2UKCWRlZiBiZV9jbG9zZSA9IHsgY2xvc2VkID0gdHJ1ZTsga25vYi51bnR1cm4gfQoJZGVmIHB1c2ggPSBiZV9vcGVuCglkZWYgcHVsbCA9IGJlX2Nsb3NlCn0KCmNsYXNzIERvb3JDbG9zZXJQdWxsKGRvb3I6IERvb3JXaXRoQ2xvc2VyKSBleHRlbmRzIFRocmVhZCB7Cgl2YXIgZG9uZTogQm9vbGVhbiA9IGZhbHNlCglvdmVycmlkZSBkZWYgcnVuID0gewoJCVRocmVhZC5zbGVlcChkb29yLmRlbGF5KQoJCWlmICghZG9uZSkgZG9vci5wdWxsCgl9Cn0KCmNsYXNzIERvb3JXaXRoQ2xvc2VyIGV4dGVuZHMgRG9vciB7Cgl2YXIgZGVsYXkgPSAzMDAKCXZhciBkZWxheWVkX3B1bGwgPSBuZXcgRG9vckNsb3NlclB1bGwodGhpcykKCW92ZXJyaWRlIGRlZiBwdXNoID0gewoJCXN1cGVyW0Rvb3JdLnB1c2gKCQlpZiAoIWRlbGF5ZWRfcHVsbC5kb25lKSBkZWxheWVkX3B1bGwuZG9uZSA9IHRydWUKCQlkZWxheWVkX3B1bGwgPSBuZXcgRG9vckNsb3NlclB1bGwodGhpcykKCQlkZWxheWVkX3B1bGwuc3RhcnQKCX0KfQoKdHJhaXQgQWJzdHJhY3REb29yU3RvcHBlciB7Cgl2YXIgc3RvcHBlcmVkOiBCb29sZWFuCglkZWYgcHVsbDogVW5pdAoJZGVmIHB1c2g6IFVuaXQKfQoKdHJhaXQgRG9vclN0b3BwZXIgZXh0ZW5kcyBBYnN0cmFjdERvb3JTdG9wcGVyIHsKCWRlZiBiZV9zdG9wcGVyZWRfb24gPSBzdG9wcGVyZWQgPSB0cnVlCglkZWYgYmVfc3RvcHBlcmVkX29mZiA9IHN0b3BwZXJlZCA9IGZhbHNlCglhYnN0cmFjdCBvdmVycmlkZSBkZWYgcHVsbCA9IGlmICghc3RvcHBlcmVkKSBzdXBlci5wdWxsCglhYnN0cmFjdCBvdmVycmlkZSBkZWYgcHVzaCA9IHsgYmVfc3RvcHBlcmVkX29mZjsgc3VwZXIucHVzaCB9Cn0KCmNsYXNzIERvb3JXaXRoU3RvcHBlciBleHRlbmRzIERvb3Igd2l0aCBEb29yU3RvcHBlciB7Cgl2YXIgc3RvcHBlcmVkID0gZmFsc2UKCW92ZXJyaWRlIGRlZiBwdWxsID0gc3VwZXIucHVsbAoJb3ZlcnJpZGUgZGVmIHB1c2ggPSBzdXBlci5wdXNoCn0KCmNsYXNzIERvb3JXaXRoQ2xvc2VyU3RvcHBlciBleHRlbmRzIERvb3JXaXRoQ2xvc2VyIHdpdGggRG9vclN0b3BwZXIgewoJdmFyIHN0b3BwZXJlZCA9IGZhbHNlCglvdmVycmlkZSBkZWYgYmVfc3RvcHBlcmVkX29mZiA9IHB1c2gKCW92ZXJyaWRlIGRlZiBwdWxsID0gc3VwZXIucHVsbAoJb3ZlcnJpZGUgZGVmIHB1c2ggPSB7CgkJc3VwZXJbRG9vclN0b3BwZXJdLmJlX3N0b3BwZXJlZF9vZmYKCQlzdXBlcltEb29yV2l0aENsb3Nlcl0ucHVzaAoJfQp9CgpvYmplY3QgTWFpbiBleHRlbmRzIEFwcCB7Cgl2YXIgZG9vciA9IG5ldyBEb29yCglwcmludGxuKCJkb29yIGlzIGEgRG9vci4uLiIpCglkb29yLmtub2IudHVybgoJcHJpbnRsbigiZG9vci5rbm9iLnR1cm47IGRvb3IuY2FuX2JlX29wZW4gPT4gIiArIGRvb3IuY2FuX2JlX29wZW4pCglkb29yLmtub2IudW50dXJuCglwcmludGxuKCJkb29yLmtub2IudW50dXJuOyBkb29yLmNhbl9iZV9vcGVuID0+ICIgKyBkb29yLmNhbl9iZV9vcGVuKQoJZG9vci5wdXNoCglwcmludGxuKCJkb29yLnB1c2g7IGRvb3IuaXNfb3BlbiA9PiAiICsgZG9vci5pc19vcGVuKQoJZG9vci5rbm9iLnR1cm47IGRvb3IucHVzaAoJcHJpbnRsbigiZG9vci5rbm9iLnR1cm47IGRvb3IucHVzaDsgZG9vci5pc19vcGVuID0+ICIgKyBkb29yLmlzX29wZW4pCglkb29yLnB1bGwKCXByaW50bG4oImRvb3IucHVsbDsgZG9vci5pc19jbG9zZSA9PiAiICsgZG9vci5pc19jbG9zZSkKCXByaW50bG4oImRvb3IuY2FuX2JlX29wZW4gPT4gIiArIGRvb3IuY2FuX2JlX29wZW4gKyAiXG4iKQoJCgl2YXIgZG9vcjIgPSBuZXcgRG9vcldpdGhDbG9zZXIKCXByaW50bG4oImRvb3IyIGlzIGEgRG9vcldpdGhDbG9zZXIuLi4iKQoJZG9vcjIua25vYi50dXJuOyBkb29yMi5wdXNoCglwcmludGxuKCJkb29yMi5rbm9iLnR1cm47IGRvb3IyLnB1c2g7IGRvb3IyLmlzX29wZW4gPT4gIiArIGRvb3IyLmlzX29wZW4pCglwcmludCgiMC4xIHNlY29uZCBhZnRlciIpCglUaHJlYWQuc2xlZXAoMTAwKQoJcHJpbnRsbigiLCBkb29yMi5pc19vcGVuID0+ICIgKyBkb29yMi5pc19vcGVuKQoJcHJpbnQoIjAuNCBzZWNvbmRzIGFmdGVyIikKCVRocmVhZC5zbGVlcCgzMDApCglwcmludGxuKCIsIGRvb3IyLmlzX29wZW4gPT4gIiArIGRvb3IyLmlzX29wZW4gKyAiXG4iKQoKCXZhciBkb29yMyA9IG5ldyBEb29yV2l0aFN0b3BwZXIKCXByaW50bG4oImRvb3IzIGlzIGEgRG9vcldpdGhTdG9wcGVyLi4uIikKCWRvb3IzLmtub2IudHVybjsgZG9vcjMucHVzaAoJcHJpbnRsbigiZG9vcjMua25vYi50dXJuOyBkb29yMy5wdXNoOyBkb29yMy5pc19vcGVuID0+ICIgKyBkb29yMy5pc19vcGVuKQoJZG9vcjMuYmVfc3RvcHBlcmVkX29uOyBkb29yMy5wdWxsCglwcmludGxuKCJkb29yMy5iZV9zdG9wcGVyZWRfb247IGRvb3IzLnB1bGw7IGRvb3IzLmlzX2Nsb3NlID0+ICIgKyBkb29yMy5pc19jbG9zZSkKCWRvb3IzLmJlX3N0b3BwZXJlZF9vZmY7IGRvb3IzLnB1bGwKCXByaW50bG4oImRvb3IzLmJlX3N0b3BwZXJlZF9vZmY7IGRvb3IzLnB1bGw7IGRvb3IzLmlzX2Nsb3NlID0+ICIgKyBkb29yMy5pc19jbG9zZSkKCWRvb3IzLmtub2IudHVybjsgZG9vcjMucHVzaAoJcHJpbnRsbigiZG9vcjMua25vYi50dXJuOyBkb29yMy5wdXNoOyBkb29yMy5pc19vcGVuID0+ICIgKyBkb29yMy5pc19vcGVuKQoJZG9vcjMuYmVfc3RvcHBlcmVkX29uOyBkb29yMy5wdWxsCglwcmludGxuKCJkb29yMy5iZV9zdG9wcGVyZWRfb247IGRvb3IzLnB1bGw7IGRvb3IzLmlzX2Nsb3NlID0+ICIgKyBkb29yMy5pc19jbG9zZSkKCWRvb3IzLnB1c2g7IGRvb3IzLnB1bGwKCXByaW50bG4oImRvb3IzLnB1c2g7IGRvb3IzLnB1bGw7IGRvb3IzLmlzX2Nsb3NlID0+ICIgKyBkb29yMy5pc19jbG9zZSArICJcbiIpCgoJdmFyIGRvb3I0ID0gbmV3IERvb3JXaXRoQ2xvc2VyU3RvcHBlcgoJcHJpbnRsbigiZG9vcjQgaXMgYSBEb29yV2l0aENsb3NlclN0b3BwZXIuLi4iKQoJZG9vcjQua25vYi50dXJuOyBkb29yNC5wdXNoCglwcmludGxuKCJkb29yNC5rbm9iLnR1cm47IGRvb3I0LnB1c2g7IGRvb3I0LmlzX29wZW4gPT4gIiArIGRvb3I0LmlzX29wZW4pCglkb29yNC5iZV9zdG9wcGVyZWRfb24KCXByaW50KCJkb29yNC5iZV9zdG9wcGVyZWRfb247IDAuNCBzZWNvbmRzIGFmdGVyIikKCVRocmVhZC5zbGVlcCg0MDApCglwcmludGxuKCIsIGRvb3I0LmlzX29wZW4gPT4gIiArIGRvb3I0LmlzX29wZW4pCglkb29yNC5iZV9zdG9wcGVyZWRfb2ZmCglwcmludCgiZG9vcjQuYmVfc3RvcHBlcmVkX29mZjsgMC40IHNlY29uZHMgYWZ0ZXIiKQoJVGhyZWFkLnNsZWVwKDQwMCkKCXByaW50bG4oIiwgZG9vcjQuaXNfb3BlbiA9PiAiICsgZG9vcjQuaXNfb3BlbikKCWRvb3I0Lmtub2IudHVybjsgZG9vcjQucHVzaAoJcHJpbnRsbigiZG9vcjQua25vYi50dXJuOyBkb29yNC5wdXNoOyBkb29yNC5pc19vcGVuID0+ICIgKyBkb29yNC5pc19vcGVuKQoJZG9vcjQuYmVfc3RvcHBlcmVkX29uCglwcmludCgiZG9vcjQuYmVfc3RvcHBlcmVkX29uOyAwLjQgc2Vjb25kcyBhZnRlciIpCglUaHJlYWQuc2xlZXAoNDAwKQoJcHJpbnRsbigiLCBkb29yNC5pc19vcGVuID0+ICIgKyBkb29yNC5pc19vcGVuKQoJZG9vcjQucHVzaAoJcHJpbnQoImRvb3I0LnB1c2g7IDAuNCBzZWNvbmRzIGFmdGVyIikKCVRocmVhZC5zbGVlcCg0MDApCglwcmludGxuKCIsIGRvb3I0LmlzX29wZW4gPT4gIiArIGRvb3I0LmlzX29wZW4gKyAiXG4iKQkKfQo=
door is a Door...
door.knob.turn; door.can_be_open => true
door.knob.unturn; door.can_be_open => false
door.push; door.is_open => false
door.knob.turn; door.push; door.is_open => true
door.pull; door.is_close => true
door.can_be_open => false
door2 is a DoorWithCloser...
door2.knob.turn; door2.push; door2.is_open => true
0.1 second after, door2.is_open => true
0.4 seconds after, door2.is_open => false
door3 is a DoorWithStopper...
door3.knob.turn; door3.push; door3.is_open => true
door3.be_stoppered_on; door3.pull; door3.is_close => false
door3.be_stoppered_off; door3.pull; door3.is_close => true
door3.knob.turn; door3.push; door3.is_open => true
door3.be_stoppered_on; door3.pull; door3.is_close => false
door3.push; door3.pull; door3.is_close => true
door4 is a DoorWithCloserStopper...
door4.knob.turn; door4.push; door4.is_open => true
door4.be_stoppered_on; 0.4 seconds after, door4.is_open => true
door4.be_stoppered_off; 0.4 seconds after, door4.is_open => false
door4.knob.turn; door4.push; door4.is_open => true
door4.be_stoppered_on; 0.4 seconds after, door4.is_open => true
door4.push; 0.4 seconds after, door4.is_open => false