├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── CONTRIBUTING.md ├── Finished ├── Behavioral │ ├── Iterator │ │ ├── books.go │ │ ├── example.go │ │ └── iterable.go │ └── Observer │ │ ├── example.go │ │ ├── observer.go │ │ └── subject.go ├── Creational │ ├── Builder │ │ ├── builder.go │ │ ├── example.go │ │ └── notification.go │ ├── Factory │ │ ├── example.go │ │ ├── factory.go │ │ ├── magazine.go │ │ ├── newspaper.go │ │ └── publication.go │ └── Singleton │ │ ├── example.go │ │ └── singleton.go └── Structural │ ├── Adapter │ ├── example.go │ ├── sammysang.go │ ├── sammysangAdapter.go │ ├── sohnee.go │ └── television.go │ └── Facade │ ├── cafe.go │ ├── coffeemachine.go │ └── example.go ├── LICENSE ├── NOTICE ├── README.md └── Start ├── Behavioral ├── Iterator │ ├── books.go │ ├── example.go │ └── iterable.go └── Observer │ ├── example.go │ ├── observer.go │ └── subject.go ├── Creational ├── Builder │ ├── builder.go │ ├── example.go │ └── notification.go ├── Factory │ ├── example.go │ ├── factory.go │ ├── magazine.go │ ├── newspaper.go │ └── publication.go └── Singleton │ ├── example.go │ └── singleton.go └── Structural ├── Adapter ├── example.go ├── sammysang.go ├── sammysangAdapter.go ├── sohnee.go └── television.go └── Facade ├── cafe.go ├── coffeemachine.go └── example.go /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Codeowners for these exercise files: 2 | # * (asterisk) deotes "all files and folders" 3 | # Example: * @producer @instructor 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | ## Issue Overview 9 | 10 | 11 | ## Describe your environment 12 | 13 | 14 | ## Steps to Reproduce 15 | 16 | 1. 17 | 2. 18 | 3. 19 | 4. 20 | 21 | ## Expected Behavior 22 | 23 | 24 | ## Current Behavior 25 | 26 | 27 | ## Possible Solution 28 | 29 | 30 | ## Screenshots / Video 31 | 32 | 33 | ## Related Issues 34 | 35 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .tmp 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | Contribution Agreement 3 | ====================== 4 | 5 | This repository does not accept pull requests (PRs). All pull requests will be closed. 6 | 7 | However, if any contributions (through pull requests, issues, feedback or otherwise) are provided, as a contributor, you represent that the code you submit is your original work or that of your employer (in which case you represent you have the right to bind your employer). By submitting code (or otherwise providing feedback), you (and, if applicable, your employer) are licensing the submitted code (and/or feedback) to LinkedIn and the open source community subject to the BSD 2-Clause license. 8 | -------------------------------------------------------------------------------- /Finished/Behavioral/Iterator/books.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // BookType represents the type of book 6 | type BookType int 7 | 8 | // Predefined Book types 9 | const ( 10 | HardCover BookType = iota 11 | SoftCover 12 | PaperBack 13 | EBook 14 | ) 15 | 16 | // Book represents data about a book 17 | type Book struct { 18 | Name string 19 | Author string 20 | PageCount int 21 | Type BookType 22 | } 23 | 24 | // Library holds the collection of books 25 | type Library struct { 26 | Collection []Book 27 | } 28 | 29 | // IterateBooks calls the given callback function 30 | // for each book in the collection 31 | func (l *Library) IterateBooks(f func(Book) error) { 32 | var err error 33 | for _, b := range l.Collection { 34 | err = f(b) 35 | if err != nil { 36 | fmt.Println("Error encountered:", err) 37 | break 38 | } 39 | } 40 | } 41 | 42 | // createIterator returns a BookIterator that can access the book 43 | // collection on demand 44 | func (l *Library) createIterator() iterator { 45 | return &BookIterator{ 46 | books: l.Collection, 47 | } 48 | } 49 | 50 | // ------------------- 51 | // Create a Library structure to hold a set of Books 52 | var lib *Library = &Library{ 53 | Collection: []Book{ 54 | { 55 | Name: "War and Peace", 56 | Author: "Leo Tolstoy", 57 | PageCount: 864, 58 | Type: HardCover, 59 | }, 60 | { 61 | Name: "Crime and Punishment", 62 | Author: "Leo Tolstoy", 63 | PageCount: 1225, 64 | Type: SoftCover, 65 | }, 66 | { 67 | Name: "Brave New World", 68 | Author: "Aldous Huxley", 69 | PageCount: 325, 70 | Type: PaperBack, 71 | }, 72 | { 73 | Name: "Catcher in the Rye", 74 | Author: "J.D. Salinger", 75 | PageCount: 206, 76 | Type: HardCover, 77 | }, 78 | { 79 | Name: "To Kill a Mockingbird", 80 | Author: "Harper Lee", 81 | PageCount: 399, 82 | Type: PaperBack, 83 | }, 84 | { 85 | Name: "The Grapes of Wrath", 86 | Author: "John Steinbeck", 87 | PageCount: 464, 88 | Type: HardCover, 89 | }, 90 | { 91 | Name: "Wuthering Heights", 92 | Author: "Emily Bronte", 93 | PageCount: 288, 94 | Type: EBook, 95 | }, 96 | }, 97 | } 98 | -------------------------------------------------------------------------------- /Finished/Behavioral/Iterator/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Iterate using a callback function 6 | func main() { 7 | // use IterateBooks to iterate via a callback function 8 | lib.IterateBooks(myBookCallback) 9 | 10 | // Use IterateBooks to iterate via anonymous function 11 | lib.IterateBooks(func(b Book) error { 12 | fmt.Println("Book author:", b.Author) 13 | return nil 14 | }) 15 | 16 | // create a BookIterator 17 | iter := lib.createIterator() 18 | for iter.hasNext() { 19 | book := iter.next() 20 | fmt.Printf("Book %+v\n", book) 21 | } 22 | } 23 | 24 | // This callback function processes an individual Book object 25 | func myBookCallback(b Book) error { 26 | fmt.Println("Book title:", b.Name) 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /Finished/Behavioral/Iterator/iterable.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // The IterableCollection interface defines the createIterator 4 | // function, which returns an iterator object 5 | type IterableCollection interface { 6 | createIterator() iterator 7 | } 8 | 9 | // The iterator interface contains the hasNext and next functions 10 | // which allow the collection to return items as needed 11 | type iterator interface { 12 | hasNext() bool 13 | next() *Book 14 | } 15 | 16 | // BookIterator is a concrete iterator for a Book collection 17 | type BookIterator struct { 18 | current int 19 | books []Book 20 | } 21 | 22 | func (b *BookIterator) hasNext() bool { 23 | if b.current < len(b.books) { 24 | return true 25 | } 26 | return false 27 | } 28 | 29 | func (b *BookIterator) next() *Book { 30 | if b.hasNext() { 31 | bk := b.books[b.current] 32 | b.current++ 33 | return &bk 34 | } 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /Finished/Behavioral/Observer/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // Construct two DataListener observers and 5 | // give each one a name 6 | listener1 := DataListener{ 7 | Name: "Listener 1", 8 | } 9 | listener2 := DataListener{ 10 | Name: "Listener 2", 11 | } 12 | 13 | // Create the DataSubject that the listeners will observe 14 | subj := &DataSubject{} 15 | // Register each listener with the DataSubject 16 | subj.registerObserver(listener1) 17 | subj.registerObserver(listener2) 18 | 19 | // Change the data in the DataSubject - this will cause the 20 | // onUpdate method of each listener to be called 21 | subj.ChangeItem("Monday!") 22 | subj.ChangeItem("Wednesday!") 23 | 24 | // Try to unregister one of the observers 25 | subj.unregisterObserver(listener2) 26 | // Change the data again, now only the first listener is called 27 | subj.ChangeItem("Friday!") 28 | } 29 | -------------------------------------------------------------------------------- /Finished/Behavioral/Observer/observer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Define the interface for an observer type 6 | type observer interface { 7 | onUpdate(data string) 8 | } 9 | 10 | // Our DataListener observer will have a name 11 | type DataListener struct { 12 | Name string 13 | } 14 | 15 | // To conform to the interface, it must have an onUpdate function 16 | func (dl *DataListener) onUpdate(data string) { 17 | fmt.Println("Listener:", dl.Name, "got data change:", data) 18 | } 19 | -------------------------------------------------------------------------------- /Finished/Behavioral/Observer/subject.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Define the interface for the observable type 4 | type observable interface { 5 | register(obs observer) 6 | unregister(obs observer) 7 | notifyAll() 8 | } 9 | 10 | // The DataSubject will have a list of listeners 11 | // and a field that gets changed, triggering them 12 | type DataSubject struct { 13 | observers []DataListener 14 | field string 15 | } 16 | 17 | // The ChangeItem function will cause the Listeners to be called 18 | func (ds *DataSubject) ChangeItem(data string) { 19 | ds.field = data 20 | 21 | ds.notifyAll() 22 | } 23 | 24 | // This function adds an observer to the list 25 | func (ds *DataSubject) registerObserver(o DataListener) { 26 | ds.observers = append(ds.observers, o) 27 | } 28 | 29 | // This function removes an observer from the list 30 | func (ds *DataSubject) unregisterObserver(o DataListener) { 31 | var newobs []DataListener 32 | for _, obs := range ds.observers { 33 | if o.Name != obs.Name { 34 | newobs = append(newobs, obs) 35 | } 36 | } 37 | ds.observers = newobs 38 | } 39 | 40 | // The notifyAll function calls all the listeners with the changed data 41 | func (ds *DataSubject) notifyAll() { 42 | for _, obs := range ds.observers { 43 | obs.onUpdate(ds.field) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Finished/Creational/Builder/builder.go: -------------------------------------------------------------------------------- 1 | package main 2 | import "fmt" 3 | 4 | // The NotificationBuilder has fields exported as well as a few methods 5 | // to demonstrate 6 | type NotificationBuilder struct { 7 | Title string 8 | Message string 9 | Image string 10 | Icon string 11 | Priority int 12 | NotType string 13 | } 14 | 15 | func newNotificationBuilder() *NotificationBuilder { 16 | return &NotificationBuilder{} 17 | } 18 | 19 | func (nb *NotificationBuilder) SetTitle(title string) { 20 | nb.Title = title 21 | } 22 | 23 | func (nb *NotificationBuilder) SetMessage(message string) { 24 | nb.Message = message 25 | } 26 | 27 | func (nb *NotificationBuilder) SetImage(image string) { 28 | nb.Image = image 29 | } 30 | 31 | func (nb *NotificationBuilder) SetIcon(icon string) { 32 | nb.Icon = icon 33 | } 34 | 35 | func (nb *NotificationBuilder) SetPriority(pri int) { 36 | nb.Priority = pri 37 | } 38 | 39 | func (nb *NotificationBuilder) SetType(notType string) { 40 | nb.NotType = notType 41 | } 42 | 43 | func (nb *NotificationBuilder) Build() (Notification, error) { 44 | if nb.Icon != "" && nb.SubTitle == "" { 45 | return nil, fmt.Errorf("You need to specify a subtitle when using an icon") 46 | } 47 | if nb.Priority > 5 { 48 | return nil, fmt.Errorf("Priority must be 0 to 5") 49 | } 50 | 51 | return Notification{ 52 | title: nb.Title, 53 | message: nb.Message, 54 | image: nb.Image, 55 | icon: nb.Icon, 56 | priority: nb.Priority, 57 | notType: nb.NotType, 58 | }, nil 59 | } 60 | -------------------------------------------------------------------------------- /Finished/Creational/Builder/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var bldr = newNotificationBuilder() 7 | bldr.SetTitle("New Notification") 8 | bldr.SetIcon("icon.png") 9 | bldr.SetSubTitle("This is a subtitle") 10 | bldr.SetImage("image.jpg") 11 | bldr.SetPriority(5) 12 | bldr.SetMessage("This is a basic notification") 13 | bldr.SetType("alert") 14 | 15 | notif, _ := bldr.Build() 16 | if err != nil { 17 | fmt.Println("Error creating the notification:", err) 18 | } else { 19 | fmt.Printf("Notification: %+v\n", notif) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Finished/Creational/Builder/notification.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // This is the finished product that is created by the builder 4 | type Notification struct { 5 | title string 6 | message string 7 | image string 8 | icon string 9 | priority int 10 | notType string 11 | } 12 | -------------------------------------------------------------------------------- /Finished/Creational/Factory/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | mag1, _ := newPublication("magazine", "Tyme", 50, "The Tymes") 7 | mag2, _ := newPublication("magazine", "Lyfe", 40, "Lyfe Inc") 8 | news1, _ := newPublication("newspaper", "The Herald", 60, "Heralders") 9 | news2, _ := newPublication("newspaper", "The Standard", 30, "Standarders") 10 | 11 | pubDetails(mag1) 12 | pubDetails(mag2) 13 | pubDetails(news1) 14 | pubDetails(news2) 15 | } 16 | 17 | func pubDetails(pub iPublication) { 18 | fmt.Printf("--------------------\n") 19 | fmt.Printf("%s\n", pub) 20 | fmt.Printf("Type: %T\n", pub) 21 | fmt.Printf("Name: %s\n", pub.getName()) 22 | fmt.Printf("Pages: %d\n", pub.getPages()) 23 | fmt.Printf("Publisher: %s\n", pub.getPublisher()) 24 | fmt.Printf("--------------------\n") 25 | } 26 | -------------------------------------------------------------------------------- /Finished/Creational/Factory/factory.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func newPublication(pubType string, name string, pg int, pub string) (iPublication, error) { 6 | // Create the right kind of publication based on the given type 7 | if pubType == "newspaper" { 8 | return createNewspaper(name, pg, pub), nil 9 | } 10 | if pubType == "magazine" { 11 | return createMagazine(name, pg, pub), nil 12 | } 13 | return nil, fmt.Errorf("No such publication type") 14 | } 15 | -------------------------------------------------------------------------------- /Finished/Creational/Factory/magazine.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Define a magazine struct and embed the publication interface 6 | type magazine struct { 7 | publication 8 | } 9 | 10 | // Define a Stringer interface that gives a string representation of the type 11 | func (m magazine) String() string { 12 | return fmt.Sprintf("This is a magazine named %s", m.name) 13 | } 14 | 15 | func createMagazine(name string, pages int, publisher string) iPublication { 16 | return &magazine{ 17 | publication: publication{ 18 | name: name, 19 | pages: pages, 20 | publisher: publisher, 21 | }, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Finished/Creational/Factory/newspaper.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Define a newspaper type and embed the publication interface 6 | type newspaper struct { 7 | publication 8 | } 9 | 10 | // Define a Stringer interface that gives a string representation of the type 11 | func (n newspaper) String() string { 12 | return fmt.Sprintf("This is a newspaper named %s", n.name) 13 | } 14 | 15 | func createNewspaper(name string, pages int, publisher string) iPublication { 16 | return &newspaper{ 17 | publication: publication{ 18 | name: name, 19 | pages: pages, 20 | publisher: publisher, 21 | }, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Finished/Creational/Factory/publication.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type iPublication interface { 4 | setName(name string) 5 | setPages(pages int) 6 | setPublisher(publisher string) 7 | getName() string 8 | getPages() int 9 | getPublisher() string 10 | } 11 | 12 | type publication struct { 13 | name string 14 | pages int 15 | publisher string 16 | } 17 | 18 | func (p *publication) setName(name string) { 19 | p.name = name 20 | } 21 | 22 | func (p *publication) setPages(pages int) { 23 | p.pages = pages 24 | } 25 | 26 | func (p *publication) setPublisher(publisher string) { 27 | p.publisher = publisher 28 | } 29 | 30 | func (p *publication) getName() string { 31 | return p.name 32 | } 33 | 34 | func (p *publication) getPages() int { 35 | return p.pages 36 | } 37 | 38 | func (p *publication) getPublisher() string { 39 | return p.publisher 40 | } 41 | -------------------------------------------------------------------------------- /Finished/Creational/Singleton/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | log := getLoggerInstance() 7 | 8 | log.SetLogLevel(1) 9 | log.Log("This is a log message") 10 | 11 | log = getLoggerInstance() 12 | log.SetLogLevel(2) 13 | log.Log("This is a log message") 14 | 15 | log = getLoggerInstance() 16 | log.SetLogLevel(3) 17 | log.Log("This is a log message") 18 | 19 | // create several goroutines that try to get the 20 | // logger instance concurrently 21 | for i := 1; i < 10; i++ { 22 | go getLoggerInstance() 23 | } 24 | // wait for input before exiting 25 | fmt.Scanln() 26 | } 27 | -------------------------------------------------------------------------------- /Finished/Creational/Singleton/singleton.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | // MyLogger is the struct we want to make a singleton 9 | type MyLogger struct { 10 | loglevel int 11 | } 12 | 13 | // Log a message using the logger 14 | func (l *MyLogger) Log(s string) { 15 | fmt.Println(l.loglevel, ":", s) 16 | } 17 | 18 | // SetLogLevel sets the log level of the logger 19 | func (l *MyLogger) SetLogLevel(level int) { 20 | l.loglevel = level 21 | } 22 | 23 | // the logger instance 24 | var logger *MyLogger 25 | 26 | // use the sync package to enforce goroutine safety 27 | var once sync.Once 28 | 29 | // the getLoggerInstance function provides global access to the 30 | // logger class instance 31 | func getLoggerInstance() *MyLogger { 32 | once.Do(func() { 33 | fmt.Println("Creating Logger Instance") 34 | logger = &MyLogger{} 35 | }) 36 | fmt.Println("Returning Logger Instance") 37 | return logger 38 | } 39 | -------------------------------------------------------------------------------- /Finished/Structural/Adapter/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // Create instances of the two TV types with some default values 7 | tv1 := &SammysangTV{ 8 | currentChan: 13, 9 | currentVolume: 35, 10 | tvOn: true, 11 | } 12 | tv2 := &SohneeTV{ 13 | vol: 20, 14 | channel: 9, 15 | isOn: true, 16 | } 17 | 18 | // Because the SohneeTV implements the "television" interface, we don't need an adapter 19 | tv2.turnOn() 20 | tv2.volumeUp() 21 | tv2.volumeDown() 22 | tv2.channelUp() 23 | tv2.channelDown() 24 | tv2.goToChannel(68) 25 | tv2.turnOff() 26 | 27 | fmt.Println("--------------------") 28 | 29 | // We need to create a SammysangTV adapter for the SammysangTV class, however 30 | // because it has an interface that's different from the one we want to use 31 | ssAdapt := &sammysangAdapter{ 32 | sstv: tv1, 33 | } 34 | ssAdapt.turnOn() 35 | ssAdapt.volumeUp() 36 | ssAdapt.volumeDown() 37 | ssAdapt.channelUp() 38 | ssAdapt.channelDown() 39 | ssAdapt.goToChannel(68) 40 | ssAdapt.turnOff() 41 | } 42 | -------------------------------------------------------------------------------- /Finished/Structural/Adapter/sammysang.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type SammysangTV struct { 6 | currentChan int 7 | currentVolume int 8 | tvOn bool 9 | } 10 | 11 | func (tv *SammysangTV) getVolume() int { 12 | fmt.Println("SammysangTV volume is", tv.currentVolume) 13 | return tv.currentVolume 14 | } 15 | 16 | func (tv *SammysangTV) setVolume(vol int) { 17 | fmt.Println("Setting SammysangTV volume to", vol) 18 | tv.currentVolume = vol 19 | } 20 | 21 | func (tv *SammysangTV) getChannel() int { 22 | fmt.Println("SammysangTV channel is", tv.currentChan) 23 | return tv.currentChan 24 | } 25 | 26 | func (tv *SammysangTV) setChannel(ch int) { 27 | fmt.Println("Setting SammysangTV channel to", ch) 28 | tv.currentChan = ch 29 | } 30 | 31 | func (tv *SammysangTV) setOnState(tvOn bool) { 32 | if tvOn == true { 33 | fmt.Println("SammysangTV is on") 34 | } else { 35 | fmt.Println("SammysangTV is off") 36 | } 37 | tv.tvOn = tvOn 38 | } 39 | -------------------------------------------------------------------------------- /Finished/Structural/Adapter/sammysangAdapter.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type sammysangAdapter struct { 4 | sstv *SammysangTV 5 | } 6 | 7 | func (ss *sammysangAdapter) turnOn() { 8 | ss.sstv.setOnState(true) 9 | } 10 | 11 | func (ss *sammysangAdapter) turnOff() { 12 | ss.sstv.setOnState(false) 13 | } 14 | 15 | func (ss *sammysangAdapter) volumeUp() int { 16 | vol := ss.sstv.getVolume() + 1 17 | ss.sstv.setVolume(vol) 18 | return vol 19 | } 20 | 21 | func (ss *sammysangAdapter) volumeDown() int { 22 | vol := ss.sstv.getVolume() - 1 23 | ss.sstv.setVolume(vol) 24 | return vol 25 | } 26 | 27 | func (ss *sammysangAdapter) channelUp() int { 28 | ch := ss.sstv.getChannel() + 1 29 | ss.sstv.setChannel(ch) 30 | return ch 31 | } 32 | 33 | func (ss *sammysangAdapter) channelDown() int { 34 | ch := ss.sstv.getChannel() - 1 35 | ss.sstv.setChannel(ch) 36 | return ch 37 | } 38 | 39 | func (ss *sammysangAdapter) goToChannel(ch int) { 40 | ss.sstv.setChannel(ch) 41 | } 42 | -------------------------------------------------------------------------------- /Finished/Structural/Adapter/sohnee.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type SohneeTV struct { 6 | vol int 7 | channel int 8 | isOn bool 9 | } 10 | 11 | func (st *SohneeTV) turnOn() { 12 | fmt.Println("SohneeTV is now on") 13 | st.isOn = true 14 | } 15 | 16 | func (st *SohneeTV) turnOff() { 17 | fmt.Println("SohneeTV is now off") 18 | st.isOn = false 19 | } 20 | 21 | func (st *SohneeTV) volumeUp() int { 22 | st.vol++ 23 | fmt.Println("Increasing SohneeTV volume to", st.vol) 24 | return st.vol 25 | } 26 | 27 | func (st *SohneeTV) volumeDown() int { 28 | st.vol-- 29 | fmt.Println("Decreasing SohneeTV volume to", st.vol) 30 | return st.vol 31 | } 32 | 33 | func (st *SohneeTV) channelUp() int { 34 | st.channel++ 35 | fmt.Println("Decreasing SohneeTV channel to", st.channel) 36 | return st.channel 37 | } 38 | 39 | func (st *SohneeTV) channelDown() int { 40 | st.channel-- 41 | fmt.Println("Decreasing SohneeTV channel to", st.channel) 42 | return st.channel 43 | } 44 | 45 | func (st *SohneeTV) goToChannel(ch int) { 46 | st.channel = ch 47 | fmt.Println("Setting SohneeTV channel to", st.channel) 48 | } 49 | -------------------------------------------------------------------------------- /Finished/Structural/Adapter/television.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type television interface { 4 | volumeUp() int 5 | volumeDown() int 6 | channelUp() int 7 | channelDown() int 8 | turnOn() 9 | turnOff() 10 | goToChannel(ch int) 11 | } 12 | -------------------------------------------------------------------------------- /Finished/Structural/Facade/cafe.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func makeAmericano(size float32) { 6 | fmt.Println("\nMaking an Americano\n--------------------") 7 | 8 | americano := &CoffeeMachine{} 9 | // determine beans amount to use - 5oz for every 8oz size 10 | beansAmount := (size / 8.0) * 5.0 11 | americano.startCoffee(beansAmount, 2) 12 | americano.grindBeans() 13 | americano.useHotWater(size) 14 | americano.endCoffee() 15 | 16 | fmt.Println("Americano is ready!") 17 | } 18 | 19 | func makeLatte(size float32, foam bool) { 20 | fmt.Println("\nMaking a Latte\n--------------------") 21 | 22 | latte := &CoffeeMachine{} 23 | // determine beans amount to use - 5oz for every 8oz size 24 | beansAmount := (size / 8.0) * 5.0 25 | latte.startCoffee(beansAmount, 4) 26 | latte.grindBeans() 27 | latte.useHotWater(size) 28 | // determine milk amount to use - 2oz for every 8oz size 29 | milk := (size / 8.0) * 2.0 30 | latte.useMilk(milk) 31 | latte.doFoam(foam) 32 | latte.endCoffee() 33 | 34 | fmt.Println("Latte is ready!") 35 | } 36 | -------------------------------------------------------------------------------- /Finished/Structural/Facade/coffeemachine.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // The CoffeeMachine struct represents an API to a hypothetical coffee maker 6 | type CoffeeMachine struct { 7 | beanAmount float32 // amount in ounces of beans to use 8 | grinderLevel int // the granularity of the bean grinder 9 | waterTemp int // temperature of the water to use 10 | waterAmt float32 // amount of water to use 11 | milkAmount float32 // amount of milk to use 12 | addFoam bool // whether to add foam or not 13 | } 14 | 15 | func (c *CoffeeMachine) startCoffee(beanAmount float32, grind int) { 16 | c.beanAmount = beanAmount 17 | c.grinderLevel = grind 18 | fmt.Println("Starting coffee order with beans:", beanAmount, "and grind level", c.grinderLevel) 19 | } 20 | 21 | func (c *CoffeeMachine) endCoffee() { 22 | fmt.Println("Ending coffee order") 23 | } 24 | 25 | func (c *CoffeeMachine) grindBeans() bool { 26 | fmt.Println("Grinding the beans:", c.beanAmount, "beans at", c.grinderLevel, "granularity") 27 | return true 28 | } 29 | 30 | func (c *CoffeeMachine) useMilk(amount float32) float32 { 31 | fmt.Println("Adding milk:", amount, "oz") 32 | c.milkAmount = amount 33 | return amount 34 | } 35 | 36 | func (c *CoffeeMachine) setWaterTemp(temp int) { 37 | fmt.Println("Setting water temp:", temp) 38 | } 39 | 40 | func (c *CoffeeMachine) useHotWater(amount float32) float32 { 41 | fmt.Println("Adding hot water:", amount) 42 | c.waterAmt = amount 43 | return amount 44 | } 45 | 46 | func (c *CoffeeMachine) doFoam(useFoam bool) { 47 | fmt.Println("Foam setting:", useFoam) 48 | c.addFoam = useFoam 49 | } 50 | -------------------------------------------------------------------------------- /Finished/Structural/Facade/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // Use the Facade Cafe API to create coffee drinks 5 | // instead of directly interacting with the complex Coffee API 6 | 7 | // Make an 8 ounce Americano 8 | makeAmericano(8.0) 9 | 10 | // Make a 12 ounce Latte 11 | makeLatte(12.0, true) 12 | } 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | LinkedIn Learning Exercise Files License Agreement 2 | ================================================== 3 | 4 | This License Agreement (the "Agreement") is a binding legal agreement 5 | between you (as an individual or entity, as applicable) and LinkedIn 6 | Corporation (“LinkedIn”). By downloading or using the LinkedIn Learning 7 | exercise files in this repository (“Licensed Materials”), you agree to 8 | be bound by the terms of this Agreement. If you do not agree to these 9 | terms, do not download or use the Licensed Materials. 10 | 11 | 1. License. 12 | - a. Subject to the terms of this Agreement, LinkedIn hereby grants LinkedIn 13 | members during their LinkedIn Learning subscription a non-exclusive, 14 | non-transferable copyright license, for internal use only, to 1) make a 15 | reasonable number of copies of the Licensed Materials, and 2) make 16 | derivative works of the Licensed Materials for the sole purpose of 17 | practicing skills taught in LinkedIn Learning courses. 18 | - b. Distribution. Unless otherwise noted in the Licensed Materials, subject 19 | to the terms of this Agreement, LinkedIn hereby grants LinkedIn members 20 | with a LinkedIn Learning subscription a non-exclusive, non-transferable 21 | copyright license to distribute the Licensed Materials, except the 22 | Licensed Materials may not be included in any product or service (or 23 | otherwise used) to instruct or educate others. 24 | 25 | 2. Restrictions and Intellectual Property. 26 | - a. You may not to use, modify, copy, make derivative works of, publish, 27 | distribute, rent, lease, sell, sublicense, assign or otherwise transfer the 28 | Licensed Materials, except as expressly set forth above in Section 1. 29 | - b. Linkedin (and its licensors) retains its intellectual property rights 30 | in the Licensed Materials. Except as expressly set forth in Section 1, 31 | LinkedIn grants no licenses. 32 | - c. You indemnify LinkedIn and its licensors and affiliates for i) any 33 | alleged infringement or misappropriation of any intellectual property rights 34 | of any third party based on modifications you make to the Licensed Materials, 35 | ii) any claims arising from your use or distribution of all or part of the 36 | Licensed Materials and iii) a breach of this Agreement. You will defend, hold 37 | harmless, and indemnify LinkedIn and its affiliates (and our and their 38 | respective employees, shareholders, and directors) from any claim or action 39 | brought by a third party, including all damages, liabilities, costs and 40 | expenses, including reasonable attorneys’ fees, to the extent resulting from, 41 | alleged to have resulted from, or in connection with: (a) your breach of your 42 | obligations herein; or (b) your use or distribution of any Licensed Materials. 43 | 44 | 3. Open source. This code may include open source software, which may be 45 | subject to other license terms as provided in the files. 46 | 47 | 4. Warranty Disclaimer. LINKEDIN PROVIDES THE LICENSED MATERIALS ON AN “AS IS” 48 | AND “AS AVAILABLE” BASIS. LINKEDIN MAKES NO REPRESENTATION OR WARRANTY, 49 | WHETHER EXPRESS OR IMPLIED, ABOUT THE LICENSED MATERIALS, INCLUDING ANY 50 | REPRESENTATION THAT THE LICENSED MATERIALS WILL BE FREE OF ERRORS, BUGS OR 51 | INTERRUPTIONS, OR THAT THE LICENSED MATERIALS ARE ACCURATE, COMPLETE OR 52 | OTHERWISE VALID. TO THE FULLEST EXTENT PERMITTED BY LAW, LINKEDIN AND ITS 53 | AFFILIATES DISCLAIM ANY IMPLIED OR STATUTORY WARRANTY OR CONDITION, INCLUDING 54 | ANY IMPLIED WARRANTY OR CONDITION OF MERCHANTABILITY OR FITNESS FOR A 55 | PARTICULAR PURPOSE, AVAILABILITY, SECURITY, TITLE AND/OR NON-INFRINGEMENT. 56 | YOUR USE OF THE LICENSED MATERIALS IS AT YOUR OWN DISCRETION AND RISK, AND 57 | YOU WILL BE SOLELY RESPONSIBLE FOR ANY DAMAGE THAT RESULTS FROM USE OF THE 58 | LICENSED MATERIALS TO YOUR COMPUTER SYSTEM OR LOSS OF DATA. NO ADVICE OR 59 | INFORMATION, WHETHER ORAL OR WRITTEN, OBTAINED BY YOU FROM US OR THROUGH OR 60 | FROM THE LICENSED MATERIALS WILL CREATE ANY WARRANTY OR CONDITION NOT 61 | EXPRESSLY STATED IN THESE TERMS. 62 | 63 | 5. Limitation of Liability. LINKEDIN SHALL NOT BE LIABLE FOR ANY INDIRECT, 64 | INCIDENTAL, SPECIAL, PUNITIVE, CONSEQUENTIAL OR EXEMPLARY DAMAGES, INCLUDING 65 | BUT NOT LIMITED TO, DAMAGES FOR LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER 66 | INTANGIBLE LOSSES . IN NO EVENT WILL LINKEDIN'S AGGREGATE LIABILITY TO YOU 67 | EXCEED $100. THIS LIMITATION OF LIABILITY SHALL: 68 | - i. APPLY REGARDLESS OF WHETHER (A) YOU BASE YOUR CLAIM ON CONTRACT, TORT, 69 | STATUTE, OR ANY OTHER LEGAL THEORY, (B) WE KNEW OR SHOULD HAVE KNOWN ABOUT 70 | THE POSSIBILITY OF SUCH DAMAGES, OR (C) THE LIMITED REMEDIES PROVIDED IN THIS 71 | SECTION FAIL OF THEIR ESSENTIAL PURPOSE; AND 72 | - ii. NOT APPLY TO ANY DAMAGE THAT LINKEDIN MAY CAUSE YOU INTENTIONALLY OR 73 | KNOWINGLY IN VIOLATION OF THESE TERMS OR APPLICABLE LAW, OR AS OTHERWISE 74 | MANDATED BY APPLICABLE LAW THAT CANNOT BE DISCLAIMED IN THESE TERMS. 75 | 76 | 6. Termination. This Agreement automatically terminates upon your breach of 77 | this Agreement or termination of your LinkedIn Learning subscription. On 78 | termination, all licenses granted under this Agreement will terminate 79 | immediately and you will delete the Licensed Materials. Sections 2-7 of this 80 | Agreement survive any termination of this Agreement. LinkedIn may discontinue 81 | the availability of some or all of the Licensed Materials at any time for any 82 | reason. 83 | 84 | 7. Miscellaneous. This Agreement will be governed by and construed in 85 | accordance with the laws of the State of California without regard to conflict 86 | of laws principles. The exclusive forum for any disputes arising out of or 87 | relating to this Agreement shall be an appropriate federal or state court 88 | sitting in the County of Santa Clara, State of California. If LinkedIn does 89 | not act to enforce a breach of this Agreement, that does not mean that 90 | LinkedIn has waived its right to enforce this Agreement. The Agreement does 91 | not create a partnership, agency relationship, or joint venture between the 92 | parties. Neither party has the power or authority to bind the other or to 93 | create any obligation or responsibility on behalf of the other. You may not, 94 | without LinkedIn’s prior written consent, assign or delegate any rights or 95 | obligations under these terms, including in connection with a change of 96 | control. Any purported assignment and delegation shall be ineffective. The 97 | Agreement shall bind and inure to the benefit of the parties, their respective 98 | successors and permitted assigns. If any provision of the Agreement is 99 | unenforceable, that provision will be modified to render it enforceable to the 100 | extent possible to give effect to the parties’ intentions and the remaining 101 | provisions will not be affected. This Agreement is the only agreement between 102 | you and LinkedIn regarding the Licensed Materials, and supersedes all prior 103 | agreements relating to the Licensed Materials. 104 | 105 | Last Updated: March 2019 106 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2021 LinkedIn Corporation 2 | All Rights Reserved. 3 | 4 | Licensed under the LinkedIn Learning Exercise File License (the "License"). 5 | See LICENSE in the project root for license information. 6 | 7 | ATTRIBUTIONS: 8 | Go 9 | https://github.com/golang/go 10 | Copyright (c) 2009 The Go Authors. 11 | License: BSD-3-Clause License 12 | https://opensource.org/licenses/BSD-3-Clause 13 | 14 | Please note, this project may automatically load third party code from external 15 | repositories (for example, NPM modules, Composer packages, or other dependencies). 16 | If so, such third party code may be subject to other license terms than as set 17 | forth above. In addition, such third party code may also depend on and load 18 | multiple tiers of dependencies. Please review the applicable licenses of the 19 | additional dependencies. 20 | 21 | 22 | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 23 | 24 | BSD License 25 | https://golang.org/LICENSE 26 | 27 | Copyright (c) 2009 The Go Authors. All rights reserved. 28 | 29 | Redistribution and use in source and binary forms, with or without 30 | modification, are permitted provided that the following conditions are 31 | met: 32 | 33 | * Redistributions of source code must retain the above copyright 34 | notice, this list of conditions and the following disclaimer. 35 | * Redistributions in binary form must reproduce the above 36 | copyright notice, this list of conditions and the following disclaimer 37 | in the documentation and/or other materials provided with the 38 | distribution. 39 | * Neither the name of Google Inc. nor the names of its 40 | contributors may be used to endorse or promote products derived from 41 | this software without specific prior written permission. 42 | 43 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 44 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 45 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 46 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 47 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 48 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 49 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 53 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go Design Patterns 2 | This is the repository for the LinkedIn Learning course Go Design Patterns. The full course is available from [LinkedIn Learning][lil-course-url]. 3 | 4 | ![Go Design Patterns][lil-thumbnail-url] 5 | 6 | Go, a multi-paradigm programming language, features design patterns that allow developers to address common problems efficiently. In this course, senior developer advocate Joe Marini covers creation, structural, and behavioral design patterns. Joe begins with an overview of design patterns and design pattern categories. Then he gives you overviews and examples of several creational patterns, including builder pattern, factory pattern, and singleton pattern. He does the same for structural patterns, covering adapter patterns and facade patterns. Joe concludes with behavioral patterns such as an observer pattern and an iterator pattern. 7 | 8 | 9 | ### Instructor 10 | 11 | Joe Marini 12 | 13 | Senior Director of Product and Engineering 14 | 15 | 16 | 17 | Check out my other courses on [LinkedIn Learning](https://www.linkedin.com/learning/instructors/joe-marini). 18 | 19 | [lil-course-url]: https://www.linkedin.com/learning/go-design-patterns 20 | [lil-thumbnail-url]: https://cdn.lynda.com/course/2880139/2880139-1627493767900-16x9.jpg 21 | -------------------------------------------------------------------------------- /Start/Behavioral/Iterator/books.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // BookType represents the type of book 6 | type BookType int 7 | 8 | // Predefined Book types 9 | const ( 10 | HardCover BookType = iota 11 | SoftCover 12 | PaperBack 13 | EBook 14 | ) 15 | 16 | // Book represents data about a book 17 | type Book struct { 18 | Name string 19 | Author string 20 | PageCount int 21 | Type BookType 22 | } 23 | 24 | // Library holds the collection of books 25 | type Library struct { 26 | Collection []Book 27 | } 28 | 29 | // TODO: IterateBooks calls the given callback function 30 | // for each book in the collection 31 | func (l *Library) IterateBooks(f func(Book) error) { 32 | // TODO: implement IterateBooks 33 | } 34 | 35 | // TODO: createIterator returns a BookIterator that can access the book 36 | // collection on demand 37 | 38 | // ------------------- 39 | // Create a Library structure to hold a set of Books 40 | var lib *Library = &Library{ 41 | Collection: []Book{ 42 | { 43 | Name: "War and Peace", 44 | Author: "Leo Tolstoy", 45 | PageCount: 864, 46 | Type: HardCover, 47 | }, 48 | { 49 | Name: "Crime and Punishment", 50 | Author: "Leo Tolstoy", 51 | PageCount: 1225, 52 | Type: SoftCover, 53 | }, 54 | { 55 | Name: "Brave New World", 56 | Author: "Aldous Huxley", 57 | PageCount: 325, 58 | Type: PaperBack, 59 | }, 60 | { 61 | Name: "Catcher in the Rye", 62 | Author: "J.D. Salinger", 63 | PageCount: 206, 64 | Type: HardCover, 65 | }, 66 | { 67 | Name: "To Kill a Mockingbird", 68 | Author: "Harper Lee", 69 | PageCount: 399, 70 | Type: PaperBack, 71 | }, 72 | { 73 | Name: "The Grapes of Wrath", 74 | Author: "John Steinbeck", 75 | PageCount: 464, 76 | Type: HardCover, 77 | }, 78 | { 79 | Name: "Wuthering Heights", 80 | Author: "Emily Bronte", 81 | PageCount: 288, 82 | Type: EBook, 83 | }, 84 | }, 85 | } 86 | -------------------------------------------------------------------------------- /Start/Behavioral/Iterator/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Iterate using a callback function 6 | func main() { 7 | // TODO: use IterateBooks to iterate via a callback function 8 | 9 | 10 | // TODO: Use IterateBooks to iterate via anonymous function 11 | 12 | 13 | // TODO: create a BookIterator 14 | } 15 | 16 | // This callback function processes an individual Book object 17 | func myBookCallback(b Book) error { 18 | fmt.Println("Book title:", b.Name) 19 | return nil 20 | } 21 | -------------------------------------------------------------------------------- /Start/Behavioral/Iterator/iterable.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // The IterableCollection interface defines the createIterator 4 | // function, which returns an iterator object 5 | type IterableCollection interface { 6 | createIterator() iterator 7 | } 8 | 9 | // The iterator interface contains the hasNext and next functions 10 | // which allow the collection to return items as needed 11 | type iterator interface { 12 | hasNext() bool 13 | next() *Book 14 | } 15 | 16 | // TODO: BookIterator is a concrete iterator for a Book collection 17 | type BookIterator struct { 18 | } 19 | 20 | func (b *BookIterator) hasNext() bool { 21 | // TODO: implement hasNext() 22 | return false 23 | } 24 | 25 | func (b *BookIterator) next() *Book { 26 | // TODO: implement next() 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /Start/Behavioral/Observer/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // Construct two DataListener observers and 5 | // give each one a name 6 | listener1 := DataListener{ 7 | Name: "Listener 1", 8 | } 9 | listener2 := DataListener{ 10 | Name: "Listener 2", 11 | } 12 | 13 | // Create the DataSubject that the listeners will observe 14 | subj := &DataSubject{} 15 | // TODO: Register each listener with the DataSubject 16 | 17 | // TODO: Change the data in the DataSubject - this will cause the 18 | // onUpdate method of each listener to be called 19 | 20 | // TODO: Try to unregister one of the observers 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Start/Behavioral/Observer/observer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Define the interface for an observer type 4 | type observer interface { 5 | onUpdate(data string) 6 | } 7 | 8 | // Our DataListener observer will have a name 9 | type DataListener struct { 10 | Name string 11 | } 12 | 13 | // TODO: To conform to the interface, it must have an onUpdate function 14 | -------------------------------------------------------------------------------- /Start/Behavioral/Observer/subject.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Define the interface for the observable type 4 | type observable interface { 5 | registerObserver(obs observer) 6 | unregisterObserver(obs observer) 7 | notifyAll() 8 | } 9 | 10 | // The DataSubject will have a list of listeners 11 | // and a field that gets changed, triggering them 12 | type DataSubject struct { 13 | observers []DataListener 14 | field string 15 | } 16 | 17 | // TODO: The ChangeItem function will cause the Listeners to be called 18 | func (ds *DataSubject) ChangeItem(data string) { 19 | 20 | } 21 | 22 | // TODO: This function adds an observer to the list 23 | func (ds *DataSubject) registerObserver(o DataListener) { 24 | 25 | } 26 | 27 | // TODO: This function removes an observer from the list 28 | func (ds *DataSubject) unregisterObserver(o DataListener) { 29 | 30 | } 31 | 32 | // TODO: The notifyAll function calls all the listeners with the changed data 33 | func (ds *DataSubject) notifyAll() { 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Start/Creational/Builder/builder.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // The NotificationBuilder has fields exported 4 | type NotificationBuilder struct { 5 | Title string 6 | SubTitle string 7 | Message string 8 | Image string 9 | Icon string 10 | Priority int 11 | NotType string 12 | } 13 | 14 | func newNotificationBuilder() *NotificationBuilder { 15 | return &NotificationBuilder{} 16 | } 17 | 18 | func (nb *NotificationBuilder) SetTitle(title string) { 19 | nb.Title = title 20 | } 21 | 22 | func (nb *NotificationBuilder) SetSubTitle(subtitle string) { 23 | nb.SubTitle = subtitle 24 | } 25 | 26 | func (nb *NotificationBuilder) SetMessage(message string) { 27 | nb.Message = message 28 | } 29 | 30 | func (nb *NotificationBuilder) SetImage(image string) { 31 | nb.Image = image 32 | } 33 | 34 | func (nb *NotificationBuilder) SetIcon(icon string) { 35 | nb.Icon = icon 36 | } 37 | 38 | func (nb *NotificationBuilder) SetPriority(pri int) { 39 | nb.Priority = pri 40 | } 41 | 42 | func (nb *NotificationBuilder) SetType(notType string) { 43 | nb.NotType = notType 44 | } 45 | 46 | // The Build method returns a fully finished Notification object 47 | func (nb *NotificationBuilder) Build() (*Notification, error) { 48 | // TODO: Error checking can be done at the Build stage 49 | 50 | // TODO: Return a newly created Notification object using the current settings 51 | 52 | return nil, nil 53 | } 54 | -------------------------------------------------------------------------------- /Start/Creational/Builder/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // TODO: Create a NotificationBuilder and use it to set properties 5 | 6 | // TODO: Use the builder to set some properties 7 | 8 | // TODO: Use the Build function to create a finished object 9 | 10 | } 11 | -------------------------------------------------------------------------------- /Start/Creational/Builder/notification.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // This is the finished product that is created by the builder 4 | type Notification struct { 5 | title string 6 | subtitle string 7 | message string 8 | image string 9 | icon string 10 | priority int 11 | notType string 12 | } 13 | -------------------------------------------------------------------------------- /Start/Creational/Factory/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | mag1, _ := newPublication("magazine", "Tyme", 50, "The Tymes") 7 | mag2, _ := newPublication("magazine", "Lyfe", 40, "Lyfe Inc") 8 | news1, _ := newPublication("newspaper", "The Herald", 60, "Heralders") 9 | news2, _ := newPublication("newspaper", "The Standard", 30, "Standarders") 10 | 11 | pubDetails(mag1) 12 | pubDetails(mag2) 13 | pubDetails(news1) 14 | pubDetails(news2) 15 | } 16 | 17 | func pubDetails(pub iPublication) { 18 | fmt.Printf("--------------------\n") 19 | fmt.Printf("%s\n", pub) 20 | fmt.Printf("Type: %T\n", pub) 21 | fmt.Printf("Name: %s\n", pub.getName()) 22 | fmt.Printf("Pages: %d\n", pub.getPages()) 23 | fmt.Printf("Publisher: %s\n", pub.getPublisher()) 24 | fmt.Printf("--------------------\n") 25 | } 26 | -------------------------------------------------------------------------------- /Start/Creational/Factory/factory.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // newPublication is a factory function that creates the specified publication type 6 | func newPublication(pubType string, name string, pg int, pub string) (iPublication, error) { 7 | // TODO: Create the right kind of publication based on the given type 8 | 9 | return nil, fmt.Errorf("No such publication type") 10 | } 11 | -------------------------------------------------------------------------------- /Start/Creational/Factory/magazine.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Define a magazine struct and embed the publication interface 6 | type magazine struct { 7 | publication 8 | } 9 | 10 | // Define a Stringer interface that gives a string representation of the type 11 | func (m magazine) String() string { 12 | return fmt.Sprintf("This is a magazine named %s", m.name) 13 | } 14 | 15 | // the createMagazine function returns a new Magazine object 16 | func createMagazine(name string, pages int, publisher string) iPublication { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Start/Creational/Factory/newspaper.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Define a newspaper type and embed the publication interface 6 | type newspaper struct { 7 | publication 8 | } 9 | 10 | // Define a Stringer interface that gives a string representation of the type 11 | func (n newspaper) String() string { 12 | return fmt.Sprintf("This is a newspaper named %s", n.name) 13 | } 14 | 15 | // the createNewspaper function returns a new Newspaper object 16 | func createNewspaper(name string, pages int, publisher string) iPublication { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Start/Creational/Factory/publication.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type iPublication interface { 4 | setName(name string) 5 | setPages(pages int) 6 | setPublisher(publisher string) 7 | getName() string 8 | getPages() int 9 | getPublisher() string 10 | } 11 | 12 | type publication struct { 13 | name string 14 | pages int 15 | publisher string 16 | } 17 | 18 | func (p *publication) setName(name string) { 19 | p.name = name 20 | } 21 | 22 | func (p *publication) setPages(pages int) { 23 | p.pages = pages 24 | } 25 | 26 | func (p *publication) setPublisher(publisher string) { 27 | p.publisher = publisher 28 | } 29 | 30 | func (p *publication) getName() string { 31 | return p.name 32 | } 33 | 34 | func (p *publication) getPages() int { 35 | return p.pages 36 | } 37 | 38 | func (p *publication) getPublisher() string { 39 | return p.publisher 40 | } 41 | -------------------------------------------------------------------------------- /Start/Creational/Singleton/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | log := getLoggerInstance() 5 | 6 | log.SetLogLevel(1) 7 | log.Log("This is a log message") 8 | 9 | log = getLoggerInstance() 10 | log.SetLogLevel(2) 11 | log.Log("This is a log message") 12 | 13 | log = getLoggerInstance() 14 | log.SetLogLevel(3) 15 | log.Log("This is a log message") 16 | 17 | // TODO: create several goroutines that try to get the 18 | // logger instance concurrently 19 | } 20 | -------------------------------------------------------------------------------- /Start/Creational/Singleton/singleton.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // TODO: use the "sync" package for the Once API 4 | import ( 5 | "fmt" 6 | ) 7 | 8 | // MyLogger is the struct we want to make a singleton 9 | type MyLogger struct { 10 | loglevel int 11 | } 12 | 13 | // Log a message using the logger 14 | func (l *MyLogger) Log(s string) { 15 | fmt.Println(l.loglevel, ":", s) 16 | } 17 | 18 | // SetLogLevel sets the log level of the logger 19 | func (l *MyLogger) SetLogLevel(level int) { 20 | l.loglevel = level 21 | } 22 | 23 | // the logger instance 24 | var logger *MyLogger 25 | 26 | // TODO: use the sync package to enforce goroutine safety 27 | 28 | // TODO: the getLoggerInstance function provides global access to the 29 | // logger class instance 30 | func getLoggerInstance() *MyLogger { 31 | return logger 32 | } 33 | -------------------------------------------------------------------------------- /Start/Structural/Adapter/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // Create instances of the two TV types with some default values 7 | tv1 := &SammysangTV{ 8 | currentChan: 13, 9 | currentVolume: 35, 10 | tvOn: true, 11 | } 12 | tv2 := &SohneeTV{ 13 | vol: 20, 14 | channel: 9, 15 | isOn: true, 16 | } 17 | 18 | // TODO: Because the SohneeTV implements the "television" interface, we don't need an adapter 19 | 20 | fmt.Println("--------------------") 21 | 22 | // TODO: We need to create a SammysangTV adapter for the SammysangTV class, however 23 | // because it has an interface that's different from the one we want to use 24 | } 25 | -------------------------------------------------------------------------------- /Start/Structural/Adapter/sammysang.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type SammysangTV struct { 6 | currentChan int 7 | currentVolume int 8 | tvOn bool 9 | } 10 | 11 | func (tv *SammysangTV) getVolume() int { 12 | fmt.Println("SammysangTV volume is", tv.currentVolume) 13 | return tv.currentVolume 14 | } 15 | 16 | func (tv *SammysangTV) setVolume(vol int) { 17 | fmt.Println("Setting SammysangTV volume to", vol) 18 | tv.currentVolume = vol 19 | } 20 | 21 | func (tv *SammysangTV) getChannel() int { 22 | fmt.Println("SammysangTV channel is", tv.currentChan) 23 | return tv.currentChan 24 | } 25 | 26 | func (tv *SammysangTV) setChannel(ch int) { 27 | fmt.Println("Setting SammysangTV channel to", ch) 28 | tv.currentChan = ch 29 | } 30 | 31 | func (tv *SammysangTV) setOnState(tvOn bool) { 32 | if tvOn == true { 33 | fmt.Println("SammysangTV is on") 34 | } else { 35 | fmt.Println("SammysangTV is off") 36 | } 37 | tv.tvOn = tvOn 38 | } 39 | -------------------------------------------------------------------------------- /Start/Structural/Adapter/sammysangAdapter.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type sammysangAdapter struct { 4 | // TODO: add a field for the SammysangTV reference 5 | } 6 | 7 | func (ss *sammysangAdapter) turnOn() { 8 | // TODO 9 | } 10 | 11 | func (ss *sammysangAdapter) turnOff() { 12 | // TODO 13 | } 14 | 15 | func (ss *sammysangAdapter) volumeUp() int { 16 | // TODO 17 | } 18 | 19 | func (ss *sammysangAdapter) volumeDown() int { 20 | // TODO 21 | } 22 | 23 | func (ss *sammysangAdapter) channelUp() int { 24 | // TODO 25 | } 26 | 27 | func (ss *sammysangAdapter) channelDown() int { 28 | // TODO 29 | } 30 | 31 | func (ss *sammysangAdapter) goToChannel(ch int) { 32 | // TODO 33 | } 34 | -------------------------------------------------------------------------------- /Start/Structural/Adapter/sohnee.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type SohneeTV struct { 6 | vol int 7 | channel int 8 | isOn bool 9 | } 10 | 11 | func (st *SohneeTV) turnOn() { 12 | fmt.Println("SohneeTV is now on") 13 | st.isOn = true 14 | } 15 | 16 | func (st *SohneeTV) turnOff() { 17 | fmt.Println("SohneeTV is now off") 18 | st.isOn = false 19 | } 20 | 21 | func (st *SohneeTV) volumeUp() int { 22 | st.vol++ 23 | fmt.Println("Increasing SohneeTV volume to", st.vol) 24 | return st.vol 25 | } 26 | 27 | func (st *SohneeTV) volumeDown() int { 28 | st.vol-- 29 | fmt.Println("Decreasing SohneeTV volume to", st.vol) 30 | return st.vol 31 | } 32 | 33 | func (st *SohneeTV) channelUp() int { 34 | st.channel++ 35 | fmt.Println("Decreasing SohneeTV channel to", st.channel) 36 | return st.channel 37 | } 38 | 39 | func (st *SohneeTV) channelDown() int { 40 | st.channel-- 41 | fmt.Println("Decreasing SohneeTV channel to", st.channel) 42 | return st.channel 43 | } 44 | 45 | func (st *SohneeTV) goToChannel(ch int) { 46 | st.channel = ch 47 | fmt.Println("Setting SohneeTV channel to", st.channel) 48 | } 49 | -------------------------------------------------------------------------------- /Start/Structural/Adapter/television.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // This is the television interface we want to use with both TV types 4 | type television interface { 5 | volumeUp() int 6 | volumeDown() int 7 | channelUp() int 8 | channelDown() int 9 | turnOn() 10 | turnOff() 11 | goToChannel(ch int) 12 | } 13 | -------------------------------------------------------------------------------- /Start/Structural/Facade/cafe.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func makeAmericano(size float32) { 6 | fmt.Println("\nMaking an Americano\n--------------------") 7 | 8 | // TODO: make an americano coffee using the coffeemachine API 9 | 10 | // determine beans amount to use - 5oz for every 8oz size 11 | 12 | fmt.Println("Americano is ready!") 13 | } 14 | 15 | func makeLatte(size float32, foam bool) { 16 | fmt.Println("\nMaking a Latte\n--------------------") 17 | 18 | // TODO: make a latte coffee using the coffeemachine API 19 | 20 | // determine beans amount to use - 5oz for every 8oz size 21 | 22 | // determine milk amount to use - 2oz for every 8oz size 23 | 24 | fmt.Println("Latte is ready!") 25 | } 26 | -------------------------------------------------------------------------------- /Start/Structural/Facade/coffeemachine.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // The CoffeeMachine struct represents an API to a hypothetical coffee maker 6 | type CoffeeMachine struct { 7 | beanAmount float32 // amount in ounces of beans to use 8 | grinderLevel int // the granularity of the bean grinder 9 | waterTemp int // temperature of the water to use 10 | waterAmt float32 // amount of water to use 11 | milkAmount float32 // amount of milk to use 12 | addFoam bool // whether to add foam or not 13 | } 14 | 15 | func (c *CoffeeMachine) startCoffee(beanAmount float32, grind int) { 16 | c.beanAmount = beanAmount 17 | c.grinderLevel = grind 18 | fmt.Println("Starting coffee order with beans:", beanAmount, "and grind level", c.grinderLevel) 19 | } 20 | 21 | func (c *CoffeeMachine) endCoffee() { 22 | fmt.Println("Ending coffee order") 23 | } 24 | 25 | func (c *CoffeeMachine) grindBeans() bool { 26 | fmt.Println("Grinding the beans:", c.beanAmount, "beans at", c.grinderLevel, "granularity") 27 | return true 28 | } 29 | 30 | func (c *CoffeeMachine) useMilk(amount float32) float32 { 31 | fmt.Println("Adding milk:", amount, "oz") 32 | c.milkAmount = amount 33 | return amount 34 | } 35 | 36 | func (c *CoffeeMachine) setWaterTemp(temp int) { 37 | fmt.Println("Setting water temp:", temp) 38 | } 39 | 40 | func (c *CoffeeMachine) useHotWater(amount float32) float32 { 41 | fmt.Println("Adding hot water:", amount) 42 | c.waterAmt = amount 43 | return amount 44 | } 45 | 46 | func (c *CoffeeMachine) doFoam(useFoam bool) { 47 | fmt.Println("Foam setting:", useFoam) 48 | c.addFoam = useFoam 49 | } 50 | -------------------------------------------------------------------------------- /Start/Structural/Facade/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // Use the Facade Cafe API to create coffee drinks 5 | // instead of directly interacting with the complex Coffee API 6 | 7 | // Make an 8 ounce Americano 8 | makeAmericano(8.0) 9 | 10 | // Make a 12 ounce Latte 11 | makeLatte(12.0, true) 12 | } 13 | --------------------------------------------------------------------------------