package main
import (
"fmt"
"time"
)
type Knob struct {
door *Door
latched bool
}
func NewKnob(d *Door) *Knob {
k := new(Knob)
k.door = d
k.latched = true
return k
}
func (k *Knob) IsLatchedOff() bool {
return !k.latched
}
func (k *Knob) Turn() {
k.latched = false
}
func (k *Knob) Unturn() {
if k.door.IsClose() { k.latched = true }
}
type Door struct {
Knob *Knob
closed bool
self Doorer
}
type Doorer interface {
IsClose() bool
IsOpen() bool
CanBeOpen() bool
Push()
Pull()
Self() Doorer
}
func NewDoor() *Door {
d := new(Door)
d.Knob = NewKnob(d)
d.closed = true
d.self = d
return d
}
func (d *Door) Self() Doorer {
return d.self
}
func (d *Door) IsClose() bool {
return d.closed
}
func (d *Door) IsOpen() bool {
return !d.closed
}
func (d *Door) CanBeOpen() bool {
return d.IsOpen() || d.Knob.IsLatchedOff()
}
func (d *Door) Push() {
if d.CanBeOpen() { d.closed = false }
}
func (d *Door) Pull() {
d.closed = true
d.Knob.Unturn()
}
type DoorCloserPull struct {
door DoorWithCloserer
Expired bool
}
type DoorWithCloserer interface {
DelayMsec() int
Self() Doorer
}
func NewDoorCloserPull(d DoorWithCloserer) *DoorCloserPull {
p := new(DoorCloserPull)
p.door = d
p.Expired = false
return p
}
func (p *DoorCloserPull) Start() {
time.
Sleep(time.
Duration(p.
door.
DelayMsec()) * time.
Millisecond) if !p.Expired { p.door.Self().Pull() }
}
type DoorWithCloser struct {
delayMsec int
delayedPull *DoorCloserPull
*Door
}
func NewDoorWithCloser() *DoorWithCloser {
d := new(DoorWithCloser)
d.Door = NewDoor()
d.self = d
d.delayMsec = 300
return d
}
func (d *DoorWithCloser) DelayMsec() int {
return d.delayMsec
}
func (d *DoorWithCloser) SetDelayMsec(v int) {
d.delayMsec = v
d.ExecDelayedPull()
}
func (d *DoorWithCloser) ExecDelayedPull() {
if d.IsOpen() {
if d.delayedPull != nil && !d.delayedPull.Expired {
d.delayedPull.Expired = true
}
d.delayedPull = NewDoorCloserPull(d)
go d.delayedPull.Start()
}
}
func (d *DoorWithCloser) Push() {
d.Door.Push()
d.ExecDelayedPull()
}
type DoorStopper struct {
door DoorWithStopperer
stoppered bool
}
type DoorWithStopperer interface {
Pull()
Push()
}
func NewDoorStopper(d DoorWithStopperer) *DoorStopper {
s := new(DoorStopper)
s.door = d
s.stoppered = false
return s
}
func (s *DoorStopper) BeStopperedOn() {
s.stoppered = true
}
func (s *DoorStopper) BeStopperedOff() {
s.stoppered = false
}
func (s *DoorStopper) Pull() {
if !s.stoppered { s.door.Pull() }
}
func (s *DoorStopper) Push() {
s.stoppered = false
s.door.Push()
}
type DoorWithStopper struct {
*Door
*DoorStopper
}
func NewDoorWithStopper() *DoorWithStopper {
d := new(DoorWithStopper)
d.Door = NewDoor()
d.self = d
d.DoorStopper = NewDoorStopper(d.Door)
return d
}
func (d *DoorWithStopper) Pull() {
d.DoorStopper.Pull()
}
func (d *DoorWithStopper) Push() {
d.DoorStopper.Push()
}
type DoorWithCloserStopper struct {
*DoorWithCloser
*DoorStopper
}
func NewDoorWithCloserStopper() *DoorWithCloserStopper {
d := new(DoorWithCloserStopper)
d.DoorWithCloser = NewDoorWithCloser()
d.self = d
d.DoorStopper = NewDoorStopper(d.DoorWithCloser)
return d
}
func (d *DoorWithCloserStopper) BeStopperedOff() {
d.DoorStopper.BeStopperedOff()
d.ExecDelayedPull()
}
func (d *DoorWithCloserStopper) Pull() {
d.DoorStopper.Pull()
}
func (d *DoorWithCloserStopper) Push() {
d.DoorStopper.Push()
}
func main(){
door1 := NewDoor()
fmt.Println("door1 is a Door...")
door1.Knob.Turn()
fmt.Println("door1.Knob.Turn(); door1.CanBeOpen() =>", door1.CanBeOpen())
door1.Knob.Unturn()
fmt.Println("door1.Knob.Unturn(); door1.CanBeOpen() =>", door1.CanBeOpen())
door1.Push()
fmt.Println("door1.Push(); door1.IsOpen() =>", door1.IsOpen())
door1.Knob.Turn(); door1.Push()
fmt.Println("door1.Knob.Turn(); door1.Push(); door1.IsOpen() =>", door1.IsOpen())
door1.Pull()
fmt.Println("door1.Pull(); door1.IsClose() => ", door1.IsClose())
fmt.Println("door1.CanBeOpen() =>", door1.CanBeOpen())
fmt.Println()
door2 := NewDoorWithCloser()
fmt.Println("door2 is a DoorWithCloser with", door2.DelayMsec(), "milliseconds delay...")
door2.Knob.Turn(); door2.Push()
fmt.Println("door2.Knob.Turn(); door2.Push(); door2.IsOpen() =>", door2.IsOpen())
fmt.Print("0.1 second after")
fmt.Println(", door2.IsOpen() =>", door2.IsOpen())
fmt.Print("0.4 seconds after")
fmt.Println(", door2.IsClose() =>", door2.IsClose())
door2.Knob.Turn(); door2.Push(); door2.SetDelayMsec(600)
fmt.Println("door2.Knob.Turn(); door2.Push(); door2.SetDelayMsec(600); door2.IsOpen() =>", door2.IsOpen())
fmt.Print("0.4 seconds after")
fmt.Println(", door2.IsClose() =>", door2.IsClose())
fmt.Print("0.7 seconds after")
fmt.Println(", door2.IsClose() =>", door2.IsClose())
fmt.Println()
door3 := NewDoorWithStopper()
fmt.Println("door3 is a DoorWithStopper...")
door3.Knob.Turn(); door3.Push()
fmt.Println("door3.Knob.Turn(); door3.Push(); door3.IsOpen() =>", door3.IsOpen())
door3.BeStopperedOn(); door3.Pull()
fmt.Println("door3.BeStopperedOn(); door3.Pull(); door3.IsClose() =>", door3.IsClose())
door3.BeStopperedOff(); door3.Pull()
fmt.Println("door3.BeStopperedOff(); door3.Pull(); door3.IsClose() =>", door3.IsClose())
door3.Knob.Turn(); door3.Push()
fmt.Println("door3.Knob.Turn(); door3.Push(); door3.IsOpen() =>", door3.IsOpen())
door3.BeStopperedOn(); door3.Pull()
fmt.Println("door3.BeStopperedOn(); door3.Pull(); door3.IsClose() =>", door3.IsClose())
door3.Push(); door3.Pull()
fmt.Println("door3.Push(); door3.Pull(); door3.IsClose() =>", door3.IsClose())
fmt.Println()
door4 := NewDoorWithCloserStopper()
fmt.Println("door4 is a DoorWithCloserStopper with", door4.DelayMsec(), "milliseconds delay...")
door4.Knob.Turn(); door4.Push()
fmt.Println("door4.Knob.Turn(); door4.Push(); door4.IsOpen() =>", door4.IsOpen())
door4.BeStopperedOn()
fmt.Print("door4.BeStopperedOn(); 0.4 seconds after")
fmt.Println(", door4.IsOpen() =>", door4.IsOpen())
door4.BeStopperedOff()
fmt.Print("door4.BeStopperedOff(); 0.4 seconds after")
fmt.Println(", door4.IsClose() =>", door4.IsClose())
door4.Knob.Turn(); door4.Push()
fmt.Println("door4.Knob.Turn(); door4.Push(); door4.IsOpen() =>", door4.IsOpen())
door4.BeStopperedOn()
fmt.Print("door4.BeStopperedOn(); 0.4 seconds after")
fmt.Println(", door4.IsOpen() =>", door4.IsOpen())
door4.Push()
fmt.Print("door4.Push(); 0.4 seconds after")
fmt.Println(", door4.IsClose() =>", door4.IsClose())
}