diff --git a/Finished/Behavioral/Iterator/books.go b/Finished/Behavioral/Iterator/books.go new file mode 100644 index 0000000..bfc38cb --- /dev/null +++ b/Finished/Behavioral/Iterator/books.go @@ -0,0 +1,97 @@ +package main + +import "fmt" + +// BookType represents the type of book +type BookType int + +// Predefined Book types +const ( + HardCover BookType = iota + SoftCover + PaperBack + EBook +) + +// Book represents data about a book +type Book struct { + Name string + Author string + PageCount int + Type BookType +} + +// Library holds the collection of books +type Library struct { + Collection []Book +} + +// IterateBooks calls the given callback function +// for each book in the collection +func (l *Library) IterateBooks(f func(Book) error) { + var err error + for _, b := range l.Collection { + err = f(b) + if err != nil { + fmt.Println("Error encountered:", err) + break + } + } +} + +// createIterator returns a BookIterator that can access the book +// collection on demand +func (l *Library) createIterator() iterator { + return &BookIterator{ + books: l.Collection, + } +} + +// ------------------- +// Create a Library structure to hold a set of Books +var lib *Library = &Library{ + Collection: []Book{ + { + Name: "War and Peace", + Author: "Leo Tolstoy", + PageCount: 864, + Type: HardCover, + }, + { + Name: "Crime and Punishment", + Author: "Leo Tolstoy", + PageCount: 1225, + Type: SoftCover, + }, + { + Name: "Brave New World", + Author: "Aldous Huxley", + PageCount: 325, + Type: PaperBack, + }, + { + Name: "Catcher in the Rye", + Author: "J.D. Salinger", + PageCount: 206, + Type: HardCover, + }, + { + Name: "To Kill a Mockingbird", + Author: "Harper Lee", + PageCount: 399, + Type: PaperBack, + }, + { + Name: "The Grapes of Wrath", + Author: "John Steinbeck", + PageCount: 464, + Type: HardCover, + }, + { + Name: "Wuthering Heights", + Author: "Emily Bronte", + PageCount: 288, + Type: EBook, + }, + }, +} diff --git a/Finished/Behavioral/Iterator/example.go b/Finished/Behavioral/Iterator/example.go new file mode 100644 index 0000000..23a6074 --- /dev/null +++ b/Finished/Behavioral/Iterator/example.go @@ -0,0 +1,28 @@ +package main + +import "fmt" + +// Iterate using a callback function +func main() { + // use IterateBooks to iterate via a callback function + lib.IterateBooks(myBookCallback) + + // Use IterateBooks to iterate via anonymous function + lib.IterateBooks(func(b Book) error { + fmt.Println("Book author:", b.Author) + return nil + }) + + // create a BookIterator + iter := lib.createIterator() + for iter.hasNext() { + book := iter.next() + fmt.Printf("Book %+v\n", book) + } +} + +// This callback function processes an individual Book object +func myBookCallback(b Book) error { + fmt.Println("Book title:", b.Name) + return nil +} diff --git a/Finished/Behavioral/Iterator/iterable.go b/Finished/Behavioral/Iterator/iterable.go new file mode 100644 index 0000000..10d3730 --- /dev/null +++ b/Finished/Behavioral/Iterator/iterable.go @@ -0,0 +1,36 @@ +package main + +// The IterableCollection interface defines the createIterator +// function, which returns an iterator object +type IterableCollection interface { + createIterator() iterator +} + +// The iterator interface contains the hasNext and next functions +// which allow the collection to return items as needed +type iterator interface { + hasNext() bool + next() *Book +} + +// BookIterator is a concrete iterator for a Book collection +type BookIterator struct { + current int + books []Book +} + +func (b *BookIterator) hasNext() bool { + if b.current < len(b.books) { + return true + } + return false +} + +func (b *BookIterator) next() *Book { + if b.hasNext() { + bk := b.books[b.current] + b.current++ + return &bk + } + return nil +} diff --git a/Finished/Behavioral/Observer/example.go b/Finished/Behavioral/Observer/example.go new file mode 100644 index 0000000..f89db89 --- /dev/null +++ b/Finished/Behavioral/Observer/example.go @@ -0,0 +1,28 @@ +package main + +func main() { + // Construct two DataListener observers and + // give each one a name + listener1 := DataListener{ + Name: "Listener 1", + } + listener2 := DataListener{ + Name: "Listener 2", + } + + // Create the DataSubject that the listeners will observe + subj := &DataSubject{} + // Register each listener with the DataSubject + subj.registerObserver(listener1) + subj.registerObserver(listener2) + + // Change the data in the DataSubject - this will cause the + // onUpdate method of each listener to be called + subj.ChangeItem("Monday!") + subj.ChangeItem("Wednesday!") + + // Try to unregister one of the observers + subj.unregisterObserver(listener2) + // Change the data again, now only the first listener is called + subj.ChangeItem("Friday!") +} diff --git a/Finished/Behavioral/Observer/observer.go b/Finished/Behavioral/Observer/observer.go new file mode 100644 index 0000000..ebf2f72 --- /dev/null +++ b/Finished/Behavioral/Observer/observer.go @@ -0,0 +1,18 @@ +package main + +import "fmt" + +// Define the interface for an observer type +type observer interface { + onUpdate(data string) +} + +// Our DataListener observer will have a name +type DataListener struct { + Name string +} + +// To conform to the interface, it must have an onUpdate function +func (dl *DataListener) onUpdate(data string) { + fmt.Println("Listener:", dl.Name, "got data change:", data) +} diff --git a/Finished/Behavioral/Observer/subject.go b/Finished/Behavioral/Observer/subject.go new file mode 100644 index 0000000..e6106dd --- /dev/null +++ b/Finished/Behavioral/Observer/subject.go @@ -0,0 +1,45 @@ +package main + +// Define the interface for the observable type +type observable interface { + register(obs observer) + unregister(obs observer) + notifyAll() +} + +// The DataSubject will have a list of listeners +// and a field that gets changed, triggering them +type DataSubject struct { + observers []DataListener + field string +} + +// The ChangeItem function will cause the Listeners to be called +func (ds *DataSubject) ChangeItem(data string) { + ds.field = data + + ds.notifyAll() +} + +// This function adds an observer to the list +func (ds *DataSubject) registerObserver(o DataListener) { + ds.observers = append(ds.observers, o) +} + +// This function removes an observer from the list +func (ds *DataSubject) unregisterObserver(o DataListener) { + var newobs []DataListener + for _, obs := range ds.observers { + if o.Name != obs.Name { + newobs = append(newobs, obs) + } + } + ds.observers = newobs +} + +// The notifyAll function calls all the listeners with the changed data +func (ds *DataSubject) notifyAll() { + for _, obs := range ds.observers { + obs.onUpdate(ds.field) + } +} diff --git a/Finished/Creational/Builder/builder.go b/Finished/Creational/Builder/builder.go new file mode 100644 index 0000000..ff0278e --- /dev/null +++ b/Finished/Creational/Builder/builder.go @@ -0,0 +1,51 @@ +package main + +// The NotificationBuilder has fields exported as well as a few methods +// to demonstrate +type NotificationBuilder struct { + Title string + Message string + Image string + Icon string + Priority int + NotType string +} + +func newNotificationBuilder() *NotificationBuilder { + return &NotificationBuilder{} +} + +func (nb *NotificationBuilder) SetTitle(title string) { + nb.Title = title +} + +func (nb *NotificationBuilder) SetMessage(message string) { + nb.Message = message +} + +func (nb *NotificationBuilder) SetImage(image string) { + nb.Image = image +} + +func (nb *NotificationBuilder) SetIcon(icon string) { + nb.Icon = icon +} + +func (nb *NotificationBuilder) SetPriority(pri int) { + nb.Priority = pri +} + +func (nb *NotificationBuilder) SetType(notType string) { + nb.NotType = notType +} + +func (nb *NotificationBuilder) Build() (Notification, error) { + return Notification{ + title: nb.Title, + message: nb.Message, + image: nb.Image, + icon: nb.Icon, + priority: nb.Priority, + notType: nb.NotType, + }, nil +} diff --git a/Finished/Creational/Builder/example.go b/Finished/Creational/Builder/example.go new file mode 100644 index 0000000..8410af5 --- /dev/null +++ b/Finished/Creational/Builder/example.go @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + var bldr = newNotificationBuilder() + bldr.SetTitle("New Notification") + bldr.SetIcon("icon 1") + bldr.SetMessage("This is a basic notification") + + notif, _ := bldr.Build() + fmt.Printf("Notification: %+v\n", notif) +} diff --git a/Finished/Creational/Builder/notification.go b/Finished/Creational/Builder/notification.go new file mode 100644 index 0000000..82575f3 --- /dev/null +++ b/Finished/Creational/Builder/notification.go @@ -0,0 +1,11 @@ +package main + +// This is the finished product that is created by the builder +type Notification struct { + title string + message string + image string + icon string + priority int + notType string +} diff --git a/Finished/Creational/Factory/example.go b/Finished/Creational/Factory/example.go new file mode 100644 index 0000000..91d18df --- /dev/null +++ b/Finished/Creational/Factory/example.go @@ -0,0 +1,25 @@ +package main + +import "fmt" + +func main() { + mag1, _ := newPublication("magazine", "Tyme", 50, "The Tymes") + mag2, _ := newPublication("magazine", "Lyfe", 40, "Lyfe Inc") + news1, _ := newPublication("newspaper", "The Herald", 60, "Heralders") + news2, _ := newPublication("newspaper", "The Standard", 30, "Standarders") + + pubDetails(mag1) + pubDetails(mag2) + pubDetails(news1) + pubDetails(news2) +} + +func pubDetails(pub iPublication) { + fmt.Printf("--------------------\n") + fmt.Printf("%s\n", pub) + fmt.Printf("Type: %T\n", pub) + fmt.Printf("Name: %s\n", pub.getName()) + fmt.Printf("Pages: %d\n", pub.getPages()) + fmt.Printf("Publisher: %s\n", pub.getPublisher()) + fmt.Printf("--------------------\n") +} diff --git a/Finished/Creational/Factory/factory.go b/Finished/Creational/Factory/factory.go new file mode 100644 index 0000000..71fc626 --- /dev/null +++ b/Finished/Creational/Factory/factory.go @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func newPublication(pubType string, name string, pg int, pub string) (iPublication, error) { + // Create the right kind of publication based on the given type + if pubType == "newspaper" { + return createNewspaper(name, pg, pub), nil + } + if pubType == "magazine" { + return createMagazine(name, pg, pub), nil + } + return nil, fmt.Errorf("No such publication type") +} diff --git a/Finished/Creational/Factory/magazine.go b/Finished/Creational/Factory/magazine.go new file mode 100644 index 0000000..c901954 --- /dev/null +++ b/Finished/Creational/Factory/magazine.go @@ -0,0 +1,23 @@ +package main + +import "fmt" + +// Define a magazine struct and embed the publication interface +type magazine struct { + publication +} + +// Define a Stringer interface that gives a string representation of the type +func (m magazine) String() string { + return fmt.Sprintf("This is a magazine named %s", m.name) +} + +func createMagazine(name string, pages int, publisher string) iPublication { + return &magazine{ + publication: publication{ + name: name, + pages: pages, + publisher: publisher, + }, + } +} diff --git a/Finished/Creational/Factory/newspaper.go b/Finished/Creational/Factory/newspaper.go new file mode 100644 index 0000000..551edf9 --- /dev/null +++ b/Finished/Creational/Factory/newspaper.go @@ -0,0 +1,23 @@ +package main + +import "fmt" + +// Define a newspaper type and embed the publication interface +type newspaper struct { + publication +} + +// Define a Stringer interface that gives a string representation of the type +func (n newspaper) String() string { + return fmt.Sprintf("This is a newspaper named %s", n.name) +} + +func createNewspaper(name string, pages int, publisher string) iPublication { + return &newspaper{ + publication: publication{ + name: name, + pages: pages, + publisher: publisher, + }, + } +} diff --git a/Finished/Creational/Factory/publication.go b/Finished/Creational/Factory/publication.go new file mode 100644 index 0000000..725f615 --- /dev/null +++ b/Finished/Creational/Factory/publication.go @@ -0,0 +1,40 @@ +package main + +type iPublication interface { + setName(name string) + setPages(pages int) + setPublisher(publisher string) + getName() string + getPages() int + getPublisher() string +} + +type publication struct { + name string + pages int + publisher string +} + +func (p *publication) setName(name string) { + p.name = name +} + +func (p *publication) setPages(pages int) { + p.pages = pages +} + +func (p *publication) setPublisher(publisher string) { + p.publisher = publisher +} + +func (p *publication) getName() string { + return p.name +} + +func (p *publication) getPages() int { + return p.pages +} + +func (p *publication) getPublisher() string { + return p.publisher +} diff --git a/Finished/Creational/Singleton/example.go b/Finished/Creational/Singleton/example.go new file mode 100644 index 0000000..aaf4517 --- /dev/null +++ b/Finished/Creational/Singleton/example.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +func main() { + log := getLoggerInstance() + + log.SetLogLevel(1) + log.Log("This is a log message") + + log = getLoggerInstance() + log.SetLogLevel(2) + log.Log("This is a log message") + + log = getLoggerInstance() + log.SetLogLevel(3) + log.Log("This is a log message") + + // create several goroutines that try to get the + // logger instance concurrently + for i := 1; i < 10; i++ { + go getLoggerInstance() + } + // wait for input before exiting + fmt.Scanln() +} diff --git a/Finished/Creational/Singleton/singleton.go b/Finished/Creational/Singleton/singleton.go new file mode 100644 index 0000000..d2364c4 --- /dev/null +++ b/Finished/Creational/Singleton/singleton.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "sync" +) + +// MyLogger is the struct we want to make a singleton +type MyLogger struct { + loglevel int +} + +// Log a message using the logger +func (l *MyLogger) Log(s string) { + fmt.Println(l.loglevel, ":", s) +} + +// SetLogLevel sets the log level of the logger +func (l *MyLogger) SetLogLevel(level int) { + l.loglevel = level +} + +// the logger instance +var logger *MyLogger + +// use the sync package to enforce goroutine safety +var once sync.Once + +// the getLoggerInstance function provides global access to the +// logger class instance +func getLoggerInstance() *MyLogger { + once.Do(func() { + fmt.Println("Creating Logger Instance") + logger = &MyLogger{} + }) + fmt.Println("Returning Logger Instance") + return logger +} diff --git a/Finished/Structural/Adapter/example.go b/Finished/Structural/Adapter/example.go new file mode 100644 index 0000000..9677642 --- /dev/null +++ b/Finished/Structural/Adapter/example.go @@ -0,0 +1,41 @@ +package main + +import "fmt" + +func main() { + // Create instances of the two TV types with some default values + tv1 := &SammysangTV{ + currentChan: 13, + currentVolume: 35, + tvOn: true, + } + tv2 := &SohneeTV{ + vol: 20, + channel: 9, + isOn: true, + } + + // Because the SohneeTV implements the "television" interface, we don't need an adapter + tv2.turnOn() + tv2.volumeUp() + tv2.volumeDown() + tv2.channelUp() + tv2.channelDown() + tv2.goToChannel(68) + tv2.turnOff() + + fmt.Println("--------------------") + + // We need to create a SammysangTV adapter for the SammysangTV class, however + // because it has an interface that's different from the one we want to use + ssAdapt := &sammysangAdapter{ + sstv: tv1, + } + ssAdapt.turnOn() + ssAdapt.volumeUp() + ssAdapt.volumeDown() + ssAdapt.channelUp() + ssAdapt.channelDown() + ssAdapt.goToChannel(68) + ssAdapt.turnOff() +} diff --git a/Finished/Structural/Adapter/sammysang.go b/Finished/Structural/Adapter/sammysang.go new file mode 100644 index 0000000..47dcdfa --- /dev/null +++ b/Finished/Structural/Adapter/sammysang.go @@ -0,0 +1,38 @@ +package main + +import "fmt" + +type SammysangTV struct { + currentChan int + currentVolume int + tvOn bool +} + +func (tv *SammysangTV) getVolume() int { + fmt.Println("SammysangTV volume is", tv.currentVolume) + return tv.currentVolume +} + +func (tv *SammysangTV) setVolume(vol int) { + fmt.Println("Setting SammysangTV volume to", vol) + tv.currentVolume = vol +} + +func (tv *SammysangTV) getChannel() int { + fmt.Println("SammysangTV channel is", tv.currentChan) + return tv.currentChan +} + +func (tv *SammysangTV) setChannel(ch int) { + fmt.Println("Setting SammysangTV channel to", ch) + tv.currentChan = ch +} + +func (tv *SammysangTV) setOnState(tvOn bool) { + if tvOn == true { + fmt.Println("SammysangTV is on") + } else { + fmt.Println("SammysangTV is off") + } + tv.tvOn = tvOn +} diff --git a/Finished/Structural/Adapter/sammysangAdapter.go b/Finished/Structural/Adapter/sammysangAdapter.go new file mode 100644 index 0000000..1b80285 --- /dev/null +++ b/Finished/Structural/Adapter/sammysangAdapter.go @@ -0,0 +1,41 @@ +package main + +type sammysangAdapter struct { + sstv *SammysangTV +} + +func (ss *sammysangAdapter) turnOn() { + ss.sstv.setOnState(true) +} + +func (ss *sammysangAdapter) turnOff() { + ss.sstv.setOnState(false) +} + +func (ss *sammysangAdapter) volumeUp() int { + vol := ss.sstv.getVolume() + 1 + ss.sstv.setVolume(vol) + return vol +} + +func (ss *sammysangAdapter) volumeDown() int { + vol := ss.sstv.getVolume() - 1 + ss.sstv.setVolume(vol) + return vol +} + +func (ss *sammysangAdapter) channelUp() int { + ch := ss.sstv.getChannel() + 1 + ss.sstv.setChannel(ch) + return ch +} + +func (ss *sammysangAdapter) channelDown() int { + ch := ss.sstv.getChannel() - 1 + ss.sstv.setChannel(ch) + return ch +} + +func (ss *sammysangAdapter) goToChannel(ch int) { + ss.sstv.setChannel(ch) +} diff --git a/Finished/Structural/Adapter/sohnee.go b/Finished/Structural/Adapter/sohnee.go new file mode 100644 index 0000000..737a360 --- /dev/null +++ b/Finished/Structural/Adapter/sohnee.go @@ -0,0 +1,48 @@ +package main + +import "fmt" + +type SohneeTV struct { + vol int + channel int + isOn bool +} + +func (st *SohneeTV) turnOn() { + fmt.Println("SohneeTV is now on") + st.isOn = true +} + +func (st *SohneeTV) turnOff() { + fmt.Println("SohneeTV is now off") + st.isOn = false +} + +func (st *SohneeTV) volumeUp() int { + st.vol++ + fmt.Println("Increasing SohneeTV volume to", st.vol) + return st.vol +} + +func (st *SohneeTV) volumeDown() int { + st.vol-- + fmt.Println("Decreasing SohneeTV volume to", st.vol) + return st.vol +} + +func (st *SohneeTV) channelUp() int { + st.channel++ + fmt.Println("Decreasing SohneeTV channel to", st.channel) + return st.channel +} + +func (st *SohneeTV) channelDown() int { + st.channel-- + fmt.Println("Decreasing SohneeTV channel to", st.channel) + return st.channel +} + +func (st *SohneeTV) goToChannel(ch int) { + st.channel = ch + fmt.Println("Setting SohneeTV channel to", st.channel) +} diff --git a/Finished/Structural/Adapter/television.go b/Finished/Structural/Adapter/television.go new file mode 100644 index 0000000..1866256 --- /dev/null +++ b/Finished/Structural/Adapter/television.go @@ -0,0 +1,11 @@ +package main + +type television interface { + volumeUp() int + volumeDown() int + channelUp() int + channelDown() int + turnOn() + turnOff() + goToChannel(ch int) +} diff --git a/Finished/Structural/Facade/cafe.go b/Finished/Structural/Facade/cafe.go new file mode 100644 index 0000000..f4d6cd3 --- /dev/null +++ b/Finished/Structural/Facade/cafe.go @@ -0,0 +1,35 @@ +package main + +import "fmt" + +func makeAmericano(size float32) { + fmt.Println("\nMaking an Americano\n--------------------") + + americano := &CoffeeMachine{} + // determine beans amount to use - 5oz for every 8oz size + beansAmount := (size / 8.0) * 5.0 + americano.startCoffee(beansAmount, 2) + americano.grindBeans() + americano.useHotWater(size) + americano.endCoffee() + + fmt.Println("Americano is ready!") +} + +func makeLatte(size float32, foam bool) { + fmt.Println("\nMaking a Latte\n--------------------") + + latte := &CoffeeMachine{} + // determine beans amount to use - 5oz for every 8oz size + beansAmount := (size / 8.0) * 5.0 + latte.startCoffee(beansAmount, 4) + latte.grindBeans() + latte.useHotWater(size) + // determine milk amount to use - 2oz for every 8oz size + milk := (size / 8.0) * 2.0 + latte.useMilk(milk) + latte.doFoam(foam) + latte.endCoffee() + + fmt.Println("Latte is ready!") +} diff --git a/Finished/Structural/Facade/coffeemachine.go b/Finished/Structural/Facade/coffeemachine.go new file mode 100644 index 0000000..662e74b --- /dev/null +++ b/Finished/Structural/Facade/coffeemachine.go @@ -0,0 +1,49 @@ +package main + +import "fmt" + +// The CoffeeMachine struct represents an API to a hypothetical coffee maker +type CoffeeMachine struct { + beanAmount float32 // amount in ounces of beans to use + grinderLevel int // the granularity of the bean grinder + waterTemp int // temperature of the water to use + waterAmt float32 // amount of water to use + milkAmount float32 // amount of milk to use + addFoam bool // whether to add foam or not +} + +func (c *CoffeeMachine) startCoffee(beanAmount float32, grind int) { + c.beanAmount = beanAmount + c.grinderLevel = grind + fmt.Println("Starting coffee order with beans:", beanAmount, "and grind level", c.grinderLevel) +} + +func (c *CoffeeMachine) endCoffee() { + fmt.Println("Ending coffee order") +} + +func (c *CoffeeMachine) grindBeans() bool { + fmt.Println("Grinding the beans:", c.beanAmount, "beans at", c.grinderLevel, "granularity") + return true +} + +func (c *CoffeeMachine) useMilk(amount float32) float32 { + fmt.Println("Adding milk:", amount, "oz") + c.milkAmount = amount + return amount +} + +func (c *CoffeeMachine) setWaterTemp(temp int) { + fmt.Println("Setting water temp:", temp) +} + +func (c *CoffeeMachine) useHotWater(amount float32) float32 { + fmt.Println("Adding hot water:", amount) + c.waterAmt = amount + return amount +} + +func (c *CoffeeMachine) doFoam(useFoam bool) { + fmt.Println("Foam setting:", useFoam) + c.addFoam = useFoam +} diff --git a/Finished/Structural/Facade/example.go b/Finished/Structural/Facade/example.go new file mode 100644 index 0000000..5576f75 --- /dev/null +++ b/Finished/Structural/Facade/example.go @@ -0,0 +1,12 @@ +package main + +func main() { + // Use the Facade Cafe API to create coffee drinks + // instead of directly interacting with the complex Coffee API + + // Make an 8 ounce Americano + makeAmericano(8.0) + + // Make a 12 ounce Latte + makeLatte(12.0, true) +} diff --git a/Start/Behavioral/Iterator/books.go b/Start/Behavioral/Iterator/books.go new file mode 100644 index 0000000..9c2138b --- /dev/null +++ b/Start/Behavioral/Iterator/books.go @@ -0,0 +1,85 @@ +package main + +import "fmt" + +// BookType represents the type of book +type BookType int + +// Predefined Book types +const ( + HardCover BookType = iota + SoftCover + PaperBack + EBook +) + +// Book represents data about a book +type Book struct { + Name string + Author string + PageCount int + Type BookType +} + +// Library holds the collection of books +type Library struct { + Collection []Book +} + +// TODO: IterateBooks calls the given callback function +// for each book in the collection +func (l *Library) IterateBooks(f func(Book) error) { + // TODO: implement IterateBooks +} + +// TODO: createIterator returns a BookIterator that can access the book +// collection on demand + +// ------------------- +// Create a Library structure to hold a set of Books +var lib *Library = &Library{ + Collection: []Book{ + { + Name: "War and Peace", + Author: "Leo Tolstoy", + PageCount: 864, + Type: HardCover, + }, + { + Name: "Crime and Punishment", + Author: "Leo Tolstoy", + PageCount: 1225, + Type: SoftCover, + }, + { + Name: "Brave New World", + Author: "Aldous Huxley", + PageCount: 325, + Type: PaperBack, + }, + { + Name: "Catcher in the Rye", + Author: "J.D. Salinger", + PageCount: 206, + Type: HardCover, + }, + { + Name: "To Kill a Mockingbird", + Author: "Harper Lee", + PageCount: 399, + Type: PaperBack, + }, + { + Name: "The Grapes of Wrath", + Author: "John Steinbeck", + PageCount: 464, + Type: HardCover, + }, + { + Name: "Wuthering Heights", + Author: "Emily Bronte", + PageCount: 288, + Type: EBook, + }, + }, +} diff --git a/Start/Behavioral/Iterator/example.go b/Start/Behavioral/Iterator/example.go new file mode 100644 index 0000000..d1a8360 --- /dev/null +++ b/Start/Behavioral/Iterator/example.go @@ -0,0 +1,20 @@ +package main + +import "fmt" + +// Iterate using a callback function +func main() { + // TODO: use IterateBooks to iterate via a callback function + + + // TODO: Use IterateBooks to iterate via anonymous function + + + // TODO: create a BookIterator +} + +// This callback function processes an individual Book object +func myBookCallback(b Book) error { + fmt.Println("Book title:", b.Name) + return nil +} diff --git a/Start/Behavioral/Iterator/iterable.go b/Start/Behavioral/Iterator/iterable.go new file mode 100644 index 0000000..e0a8f79 --- /dev/null +++ b/Start/Behavioral/Iterator/iterable.go @@ -0,0 +1,28 @@ +package main + +// The IterableCollection interface defines the createIterator +// function, which returns an iterator object +type IterableCollection interface { + createIterator() iterator +} + +// The iterator interface contains the hasNext and next functions +// which allow the collection to return items as needed +type iterator interface { + hasNext() bool + next() *Book +} + +// TODO: BookIterator is a concrete iterator for a Book collection +type BookIterator struct { +} + +func (b *BookIterator) hasNext() bool { + // TODO: implement hasNext() + return false +} + +func (b *BookIterator) next() *Book { + // TODO: implement next() + return nil +} diff --git a/Start/Behavioral/Observer/example.go b/Start/Behavioral/Observer/example.go new file mode 100644 index 0000000..9db2914 --- /dev/null +++ b/Start/Behavioral/Observer/example.go @@ -0,0 +1,22 @@ +package main + +func main() { + // Construct two DataListener observers and + // give each one a name + listener1 := DataListener{ + Name: "Listener 1", + } + listener2 := DataListener{ + Name: "Listener 2", + } + + // Create the DataSubject that the listeners will observe + subj := &DataSubject{} + // TODO: Register each listener with the DataSubject + + // TODO: Change the data in the DataSubject - this will cause the + // onUpdate method of each listener to be called + + // TODO: Try to unregister one of the observers + +} diff --git a/Start/Behavioral/Observer/observer.go b/Start/Behavioral/Observer/observer.go new file mode 100644 index 0000000..fff74e5 --- /dev/null +++ b/Start/Behavioral/Observer/observer.go @@ -0,0 +1,13 @@ +package main + +// Define the interface for an observer type +type observer interface { + onUpdate(data string) +} + +// Our DataListener observer will have a name +type DataListener struct { + Name string +} + +// TODO: To conform to the interface, it must have an onUpdate function diff --git a/Start/Behavioral/Observer/subject.go b/Start/Behavioral/Observer/subject.go new file mode 100644 index 0000000..34d9316 --- /dev/null +++ b/Start/Behavioral/Observer/subject.go @@ -0,0 +1,35 @@ +package main + +// Define the interface for the observable type +type observable interface { + registerObserver(obs observer) + unregisterObserver(obs observer) + notifyAll() +} + +// The DataSubject will have a list of listeners +// and a field that gets changed, triggering them +type DataSubject struct { + observers []DataListener + field string +} + +// TODO: The ChangeItem function will cause the Listeners to be called +func (ds *DataSubject) ChangeItem(data string) { + +} + +// TODO: This function adds an observer to the list +func (ds *DataSubject) registerObserver(o DataListener) { + +} + +// TODO: This function removes an observer from the list +func (ds *DataSubject) unregisterObserver(o DataListener) { + +} + +// TODO: The notifyAll function calls all the listeners with the changed data +func (ds *DataSubject) notifyAll() { + +} diff --git a/Start/Creational/Builder/builder.go b/Start/Creational/Builder/builder.go new file mode 100644 index 0000000..dfc04b3 --- /dev/null +++ b/Start/Creational/Builder/builder.go @@ -0,0 +1,53 @@ +package main + +// The NotificationBuilder has fields exported +type NotificationBuilder struct { + Title string + SubTitle string + Message string + Image string + Icon string + Priority int + NotType string +} + +func newNotificationBuilder() *NotificationBuilder { + return &NotificationBuilder{} +} + +func (nb *NotificationBuilder) SetTitle(title string) { + nb.Title = title +} + +func (nb *NotificationBuilder) SetSubTitle(subtitle string) { + nb.SubTitle = subtitle +} + +func (nb *NotificationBuilder) SetMessage(message string) { + nb.Message = message +} + +func (nb *NotificationBuilder) SetImage(image string) { + nb.Image = image +} + +func (nb *NotificationBuilder) SetIcon(icon string) { + nb.Icon = icon +} + +func (nb *NotificationBuilder) SetPriority(pri int) { + nb.Priority = pri +} + +func (nb *NotificationBuilder) SetType(notType string) { + nb.NotType = notType +} + +// The Build method returns a fully finished Notification object +func (nb *NotificationBuilder) Build() (*Notification, error) { + // TODO: Error checking can be done at the Build stage + + // TODO: Return a newly created Notification object using the current settings + + return nil, nil +} diff --git a/Start/Creational/Builder/example.go b/Start/Creational/Builder/example.go new file mode 100644 index 0000000..9254e1d --- /dev/null +++ b/Start/Creational/Builder/example.go @@ -0,0 +1,10 @@ +package main + +func main() { + // TODO: Create a NotificationBuilder and use it to set properties + + // TODO: Use the builder to set some properties + + // TODO: Use the Build function to create a finished object + +} diff --git a/Start/Creational/Builder/notification.go b/Start/Creational/Builder/notification.go new file mode 100644 index 0000000..c56089b --- /dev/null +++ b/Start/Creational/Builder/notification.go @@ -0,0 +1,12 @@ +package main + +// This is the finished product that is created by the builder +type Notification struct { + title string + subtitle string + message string + image string + icon string + priority int + notType string +} diff --git a/Start/Creational/Factory/example.go b/Start/Creational/Factory/example.go new file mode 100644 index 0000000..91d18df --- /dev/null +++ b/Start/Creational/Factory/example.go @@ -0,0 +1,25 @@ +package main + +import "fmt" + +func main() { + mag1, _ := newPublication("magazine", "Tyme", 50, "The Tymes") + mag2, _ := newPublication("magazine", "Lyfe", 40, "Lyfe Inc") + news1, _ := newPublication("newspaper", "The Herald", 60, "Heralders") + news2, _ := newPublication("newspaper", "The Standard", 30, "Standarders") + + pubDetails(mag1) + pubDetails(mag2) + pubDetails(news1) + pubDetails(news2) +} + +func pubDetails(pub iPublication) { + fmt.Printf("--------------------\n") + fmt.Printf("%s\n", pub) + fmt.Printf("Type: %T\n", pub) + fmt.Printf("Name: %s\n", pub.getName()) + fmt.Printf("Pages: %d\n", pub.getPages()) + fmt.Printf("Publisher: %s\n", pub.getPublisher()) + fmt.Printf("--------------------\n") +} diff --git a/Start/Creational/Factory/factory.go b/Start/Creational/Factory/factory.go new file mode 100644 index 0000000..0586c43 --- /dev/null +++ b/Start/Creational/Factory/factory.go @@ -0,0 +1,10 @@ +package main + +import "fmt" + +// newPublication is a factory function that creates the specified publication type +func newPublication(pubType string, name string, pg int, pub string) (iPublication, error) { + // TODO: Create the right kind of publication based on the given type + + return nil, fmt.Errorf("No such publication type") +} diff --git a/Start/Creational/Factory/magazine.go b/Start/Creational/Factory/magazine.go new file mode 100644 index 0000000..d136984 --- /dev/null +++ b/Start/Creational/Factory/magazine.go @@ -0,0 +1,18 @@ +package main + +import "fmt" + +// Define a magazine struct and embed the publication interface +type magazine struct { + publication +} + +// Define a Stringer interface that gives a string representation of the type +func (m magazine) String() string { + return fmt.Sprintf("This is a magazine named %s", m.name) +} + +// the createMagazine function returns a new Magazine object +func createMagazine(name string, pages int, publisher string) iPublication { + +} diff --git a/Start/Creational/Factory/newspaper.go b/Start/Creational/Factory/newspaper.go new file mode 100644 index 0000000..824946e --- /dev/null +++ b/Start/Creational/Factory/newspaper.go @@ -0,0 +1,18 @@ +package main + +import "fmt" + +// Define a newspaper type and embed the publication interface +type newspaper struct { + publication +} + +// Define a Stringer interface that gives a string representation of the type +func (n newspaper) String() string { + return fmt.Sprintf("This is a newspaper named %s", n.name) +} + +// the createNewspaper function returns a new Newspaper object +func createNewspaper(name string, pages int, publisher string) iPublication { + +} diff --git a/Start/Creational/Factory/publication.go b/Start/Creational/Factory/publication.go new file mode 100644 index 0000000..725f615 --- /dev/null +++ b/Start/Creational/Factory/publication.go @@ -0,0 +1,40 @@ +package main + +type iPublication interface { + setName(name string) + setPages(pages int) + setPublisher(publisher string) + getName() string + getPages() int + getPublisher() string +} + +type publication struct { + name string + pages int + publisher string +} + +func (p *publication) setName(name string) { + p.name = name +} + +func (p *publication) setPages(pages int) { + p.pages = pages +} + +func (p *publication) setPublisher(publisher string) { + p.publisher = publisher +} + +func (p *publication) getName() string { + return p.name +} + +func (p *publication) getPages() int { + return p.pages +} + +func (p *publication) getPublisher() string { + return p.publisher +} diff --git a/Start/Creational/Singleton/example.go b/Start/Creational/Singleton/example.go new file mode 100644 index 0000000..23bf827 --- /dev/null +++ b/Start/Creational/Singleton/example.go @@ -0,0 +1,19 @@ +package main + +func main() { + log := getLoggerInstance() + + log.SetLogLevel(1) + log.Log("This is a log message") + + log = getLoggerInstance() + log.SetLogLevel(2) + log.Log("This is a log message") + + log = getLoggerInstance() + log.SetLogLevel(3) + log.Log("This is a log message") + + // TODO: create several goroutines that try to get the + // logger instance concurrently +} diff --git a/Start/Creational/Singleton/singleton.go b/Start/Creational/Singleton/singleton.go new file mode 100644 index 0000000..3c418a7 --- /dev/null +++ b/Start/Creational/Singleton/singleton.go @@ -0,0 +1,32 @@ +package main + +// TODO: use the "sync" package for the Once API +import ( + "fmt" +) + +// MyLogger is the struct we want to make a singleton +type MyLogger struct { + loglevel int +} + +// Log a message using the logger +func (l *MyLogger) Log(s string) { + fmt.Println(l.loglevel, ":", s) +} + +// SetLogLevel sets the log level of the logger +func (l *MyLogger) SetLogLevel(level int) { + l.loglevel = level +} + +// the logger instance +var logger *MyLogger + +// TODO: use the sync package to enforce goroutine safety + +// TODO: the getLoggerInstance function provides global access to the +// logger class instance +func getLoggerInstance() *MyLogger { + return logger +} diff --git a/Start/Structural/Adapter/example.go b/Start/Structural/Adapter/example.go new file mode 100644 index 0000000..5f0c325 --- /dev/null +++ b/Start/Structural/Adapter/example.go @@ -0,0 +1,24 @@ +package main + +import "fmt" + +func main() { + // Create instances of the two TV types with some default values + tv1 := &SammysangTV{ + currentChan: 13, + currentVolume: 35, + tvOn: true, + } + tv2 := &SohneeTV{ + vol: 20, + channel: 9, + isOn: true, + } + + // TODO: Because the SohneeTV implements the "television" interface, we don't need an adapter + + fmt.Println("--------------------") + + // TODO: We need to create a SammysangTV adapter for the SammysangTV class, however + // because it has an interface that's different from the one we want to use +} diff --git a/Start/Structural/Adapter/sammysang.go b/Start/Structural/Adapter/sammysang.go new file mode 100644 index 0000000..47dcdfa --- /dev/null +++ b/Start/Structural/Adapter/sammysang.go @@ -0,0 +1,38 @@ +package main + +import "fmt" + +type SammysangTV struct { + currentChan int + currentVolume int + tvOn bool +} + +func (tv *SammysangTV) getVolume() int { + fmt.Println("SammysangTV volume is", tv.currentVolume) + return tv.currentVolume +} + +func (tv *SammysangTV) setVolume(vol int) { + fmt.Println("Setting SammysangTV volume to", vol) + tv.currentVolume = vol +} + +func (tv *SammysangTV) getChannel() int { + fmt.Println("SammysangTV channel is", tv.currentChan) + return tv.currentChan +} + +func (tv *SammysangTV) setChannel(ch int) { + fmt.Println("Setting SammysangTV channel to", ch) + tv.currentChan = ch +} + +func (tv *SammysangTV) setOnState(tvOn bool) { + if tvOn == true { + fmt.Println("SammysangTV is on") + } else { + fmt.Println("SammysangTV is off") + } + tv.tvOn = tvOn +} diff --git a/Start/Structural/Adapter/sammysangAdapter.go b/Start/Structural/Adapter/sammysangAdapter.go new file mode 100644 index 0000000..afa91b9 --- /dev/null +++ b/Start/Structural/Adapter/sammysangAdapter.go @@ -0,0 +1,49 @@ +package main + +type sammysangAdapter struct { + // TODO: add a field for the SammysangTV reference + sstv *SammysangTV +} + +func (ss *sammysangAdapter) turnOn() { + // TODO + ss.sstv.setOnState(true) +} + +func (ss *sammysangAdapter) turnOff() { + // TODO + ss.sstv.setOnState(false) +} + +func (ss *sammysangAdapter) volumeUp() int { + // TODO + vol := ss.sstv.getVolume() + 1 + ss.sstv.setVolume(vol) + return vol +} + +func (ss *sammysangAdapter) volumeDown() int { + // TODO + vol := ss.sstv.getVolume() - 1 + ss.sstv.setVolume(vol) + return vol +} + +func (ss *sammysangAdapter) channelUp() int { + // TODO + ch := ss.sstv.getChannel() + 1 + ss.sstv.setChannel(ch) + return ch +} + +func (ss *sammysangAdapter) channelDown() int { + // TODO + ch := ss.sstv.getChannel() - 1 + ss.sstv.setChannel(ch) + return ch +} + +func (ss *sammysangAdapter) goToChannel(ch int) { + // TODO + ss.sstv.setChannel(ch) +} diff --git a/Start/Structural/Adapter/sohnee.go b/Start/Structural/Adapter/sohnee.go new file mode 100644 index 0000000..737a360 --- /dev/null +++ b/Start/Structural/Adapter/sohnee.go @@ -0,0 +1,48 @@ +package main + +import "fmt" + +type SohneeTV struct { + vol int + channel int + isOn bool +} + +func (st *SohneeTV) turnOn() { + fmt.Println("SohneeTV is now on") + st.isOn = true +} + +func (st *SohneeTV) turnOff() { + fmt.Println("SohneeTV is now off") + st.isOn = false +} + +func (st *SohneeTV) volumeUp() int { + st.vol++ + fmt.Println("Increasing SohneeTV volume to", st.vol) + return st.vol +} + +func (st *SohneeTV) volumeDown() int { + st.vol-- + fmt.Println("Decreasing SohneeTV volume to", st.vol) + return st.vol +} + +func (st *SohneeTV) channelUp() int { + st.channel++ + fmt.Println("Decreasing SohneeTV channel to", st.channel) + return st.channel +} + +func (st *SohneeTV) channelDown() int { + st.channel-- + fmt.Println("Decreasing SohneeTV channel to", st.channel) + return st.channel +} + +func (st *SohneeTV) goToChannel(ch int) { + st.channel = ch + fmt.Println("Setting SohneeTV channel to", st.channel) +} diff --git a/Start/Structural/Adapter/television.go b/Start/Structural/Adapter/television.go new file mode 100644 index 0000000..c9007f8 --- /dev/null +++ b/Start/Structural/Adapter/television.go @@ -0,0 +1,12 @@ +package main + +// This is the television interface we want to use with both TV types +type television interface { + volumeUp() int + volumeDown() int + channelUp() int + channelDown() int + turnOn() + turnOff() + goToChannel(ch int) +} diff --git a/Start/Structural/Facade/cafe.go b/Start/Structural/Facade/cafe.go new file mode 100644 index 0000000..4f6fe49 --- /dev/null +++ b/Start/Structural/Facade/cafe.go @@ -0,0 +1,25 @@ +package main + +import "fmt" + +func makeAmericano(size float32) { + fmt.Println("\nMaking an Americano\n--------------------") + + // TODO: make an americano coffee using the coffeemachine API + + // determine beans amount to use - 5oz for every 8oz size + + fmt.Println("Americano is ready!") +} + +func makeLatte(size float32, foam bool) { + fmt.Println("\nMaking a Latte\n--------------------") + + // TODO: make a latte coffee using the coffeemachine API + + // determine beans amount to use - 5oz for every 8oz size + + // determine milk amount to use - 2oz for every 8oz size + + fmt.Println("Latte is ready!") +} diff --git a/Start/Structural/Facade/coffeemachine.go b/Start/Structural/Facade/coffeemachine.go new file mode 100644 index 0000000..662e74b --- /dev/null +++ b/Start/Structural/Facade/coffeemachine.go @@ -0,0 +1,49 @@ +package main + +import "fmt" + +// The CoffeeMachine struct represents an API to a hypothetical coffee maker +type CoffeeMachine struct { + beanAmount float32 // amount in ounces of beans to use + grinderLevel int // the granularity of the bean grinder + waterTemp int // temperature of the water to use + waterAmt float32 // amount of water to use + milkAmount float32 // amount of milk to use + addFoam bool // whether to add foam or not +} + +func (c *CoffeeMachine) startCoffee(beanAmount float32, grind int) { + c.beanAmount = beanAmount + c.grinderLevel = grind + fmt.Println("Starting coffee order with beans:", beanAmount, "and grind level", c.grinderLevel) +} + +func (c *CoffeeMachine) endCoffee() { + fmt.Println("Ending coffee order") +} + +func (c *CoffeeMachine) grindBeans() bool { + fmt.Println("Grinding the beans:", c.beanAmount, "beans at", c.grinderLevel, "granularity") + return true +} + +func (c *CoffeeMachine) useMilk(amount float32) float32 { + fmt.Println("Adding milk:", amount, "oz") + c.milkAmount = amount + return amount +} + +func (c *CoffeeMachine) setWaterTemp(temp int) { + fmt.Println("Setting water temp:", temp) +} + +func (c *CoffeeMachine) useHotWater(amount float32) float32 { + fmt.Println("Adding hot water:", amount) + c.waterAmt = amount + return amount +} + +func (c *CoffeeMachine) doFoam(useFoam bool) { + fmt.Println("Foam setting:", useFoam) + c.addFoam = useFoam +} diff --git a/Start/Structural/Facade/example.go b/Start/Structural/Facade/example.go new file mode 100644 index 0000000..5576f75 --- /dev/null +++ b/Start/Structural/Facade/example.go @@ -0,0 +1,12 @@ +package main + +func main() { + // Use the Facade Cafe API to create coffee drinks + // instead of directly interacting with the complex Coffee API + + // Make an 8 ounce Americano + makeAmericano(8.0) + + // Make a 12 ounce Latte + makeLatte(12.0, true) +}