Go for Object Oriented Programmers or Object Oriented Programming without Objects

Post on 08-Sep-2014

4.544 views 4 download

Tags:

description

Object Oriented (OO) programming has dominated software engineering for the last two decades. The paradigm built on powerful concepts such as Encapsulation, Inheritance, and Polymoprhism has been internalized by the majority of software engineers. Although Go is not OO in the strict sense, we can continue to leverage the skills we’ve honed as OO engineers to come up with simple and solid designs. Gopher Steve Francia, Author of [Hugo](http://hugo.spf13.com), [Cobra](http://github.com/spf13/cobra), and many other popular Go packages makes these difficult concepts accessible for everyone. If you’re a OO programmer, especially one with a background with dynamic languages and are curious about go then this talk is for you. We will cover everything you need to know to leverage your existing skills and quickly start coding in go including: How to use our Object Oriented programming fundamentals in go Static and pseudo dynamic typing in go Building fluent interfaces in go Using go interfaces and duck typing to simplify architecture Common mistakes made by those coming to go from other OO languages (Ruby, Python, Javascript, etc.), Principles of good design in go.

Transcript of Go for Object Oriented Programmers or Object Oriented Programming without Objects

func main() { r := Rect{width: 10, height: 5} x := Rect{width: 7, height:10} rs := Rects{r, x} fmt.Println("r's area: ", r.Area()) fmt.Println("x's area: ", x.Area()) fmt.Println("total area: ", rs.Area()) }

In Action

http://play.golang.org/p/G1OWXPGvc3

func main() { var x Foo !

x = func() int { return 1 } !

fmt.Println(x()) fmt.Println(x.Add(3)) }

In Action

http://play.golang.org/p/YGrdCG3SlI

– Wikipedia

A language is usually considered object-based if it includes the basic capabilities for an

object: identity, properties, and attributes.

A language is considered object-oriented if it is object-based and also has the capability of

polymorphism and inheritance.

Inheritance• Provides reuse of objects

• Classes are created in hierarchies

• Inheritance lets the structure and methods in one class pass down the hierarchy

Go’s approach• Go explicitly avoided inheritance

• Go strictly follows the composition over inheritance principle

• Composition through embedded types

Composition• Provides reuse of Objects

• One object is declared by including other objects

• Composition lets the structure and methods in one class be pulled into another

type Person struct {

Name string

Address }

!

!

type Address struct {

Number string

Street string

City string

State string

Zip string

}

Embedding Types

Inner Type

func (a *Address) String() string {

return a.Number+" "+a.Street+"\n"+ a.City+", "+a.State+" "+a.Zip+"\n"

}

Declaring a Method

func main() { p := Person{ Name: "Steve", Address: Address{ Number: "13", Street: "Main", City: "Gotham", State: "NY", Zip: "01313", }, } }

Declare using Composite Literal

func main() { p := Person{ Name: "Steve", Address: Address{ Number: "13", Street: "Main", City: "Gotham", State: "NY", Zip: "01313", }, }

fmt.Println(p.String())

In Action

http://play.golang.org/p/9beVY9jNlW

Promotion• Promotion looks to see if a single inner type can

satisify the request and “promotes” it

• Embedded fields & methods are “promoted”

• Promotion only occurs during usage, not declaration

• Promoted methods are considered for interface adherance

func (a *Address) String() string { return a.Number+" "+a.Street+"\n"+ a.City+", "+a.State+" "+a.Zip+"\n" } !

func (p *Person) String() string { return p.Name + "\n" + p.Address.String() }

Not Overloading

func main() { p := Person{ Name: "Steve", Address: Address{ Number: "13", Street: "Main", City: "Gotham", State: "NY", Zip: "01313", }, } ! fmt.Println(p.String()) fmt.Println(p.Address.String()) }

Both Methods Available

http://play.golang.org/p/Aui0nGa5Xi

func isValidAddress(a *Address) bool { return a.Street != "" } !func main() { p := Person{ Name: "Steve", Address: Address{ Number: "13", Street: "Main", City: "Gotham", State: "NY", Zip: "01313"}} ! fmt.Println(isValidAddress(p)) // cannot use p (type Person) as type Address // in argument to isValidAddress fmt.Println(isValidAddress(p.Address)) }

Types Remain Distinct

http://play.golang.org/p/KYjXZxNBcQ

Polymorphism• “The provision of a single interface to

entities of different types”

• Typically implmented via Generics, Overloading and/or Subtyping

Go’s approach• Go explicitly avoided subtyping &

overloading

• Go does not provide Generics (yet)

• Go’s interface provide polymorphic capabilities

Interfaces• A list of required methods

• Structural vs Nominal typing

• ‘‘If something can do this, then it can be used here”

• Convention is call it a Something-er

func main() { r := &Rect{width: 10, height: 5} x := &Rect{width: 7, height: 10} rs := &Rects{r, x} Describe(r) Describe(x) Describe(rs) }

In Action

http://play.golang.org/p/WL77LihUwi

–James Gosling (creator of Java)

“If you could do Java over again, what would you change?” “I’d leave out classes,” he replied. After the

laughter died down, he explained that the real problem wasn’t classes per se, but rather implementation inheritance (the extends

relationship). Interface inheritance (the implements relationship) is preferable. You should avoid

implementation inheritance whenever possible.

io.Reader• Interface

• Read reads up to len(p) bytes into p

• Returns the # of bytes read & any error

• Does not dictate how Read() is implemented

• Used by os.File, bytes.Buffer, net.Conn, http.Request.Body, loads more

io.Writer• Interface

• Write writes up to len(p) bytes into p

• Returns the # of bytes written & any error

• Does not dictate how Write() is implemented

• Used by os.File, bytes.Buffer, net.Conn, http.Response.Body, loads more

func MarshalGzippedJSON(r io.Reader, v interface{}) error { raw, err := gzip.NewReader(r) if err != nil { return err } return json.NewDecoder(raw).Decode(&v) }

io.Reader in Action

f, err := os.Open("myfile.json.gz") if err != nil { log.Fatalln(err) } defer f.Close() m = make(map[string]interface{}) MarshalGzippedJSON(f, &m)

Reading a json.gz file

Practical Interoperability• Gzip.NewReader(io.Reader)

• Works on files, http requests, byte buffers, network connections, …anything you create

• Nothing special needed in gzip to be able to do this… Simply call Read(n) and leave the abstracting to the implementor

func main() { resp, err := http.Get("...") if err != nil { log.Fatalln(err) } defer resp.Body.Close() out, err := os.Create("filename.ext") if err != nil { log.Fatalln(err) } defer out.Close() io.Copy(out, resp.Body) // out io.Writer, resp.Body io.Reader }

Pipe http response to file

— Steve Jobs

Simple can be harder than complex: You have to work hard

to get your thinking clean to make it simple. But it's worth it in the end because once you get there, you can move mountains.