Object oriented programming in go

Post on 14-Jul-2015

449 views 2 download

Transcript of Object oriented programming in go

Object-Oriented Programming inGoGo Seoul Meetup24 January 2015

장재휴Developer, Purpleworks

Who am I

Elandsystems ➜ purpleworks

Ruby, C#, Go

Agenda

OOP in Go

What is "Object Oriented" (wikipedia)

A language is usually considered object-based if it includes the basic capabilitiesfor an object: identity, properties, and attributes

A language is considered object-oriented if it is object-based and also has thecapability of polymorphism and inheritance

Is Go Object-based Language?

What is an "Object" (wikipedia)

An object is an abstract data type that has state(data) and behavior(code)

Object in Go (via Custom Type & Method)

package main

import "fmt"

// Type Declarationtype Item struct {type Item struct { name string price float64 quantity int}

// Method Declarationfunc (t Item) Cost() float64 {func (t Item) Cost() float64 { return t.price * float64(t.quantity)}

// In Actionfunc main() { shirt := Item{name: "Men's Slim-Fit Shirt", price: 25000, quantity: 3} fmt.Println("cost: ", shirt.Cost())fmt.Println("cost: ", shirt.Cost())} Run

Custom Type of built-in Type

// Type Declarationtype Items []Itemtype Items []Item

// Method Declarationfunc (ts Items) Cost() float64 {func (ts Items) Cost() float64 { var c float64 for _, t := range ts { c += t.Cost() } return c}

// In Actionfunc main() { shirt := Item{name: "Men's Slim-Fit Shirt", price: 25000, quantity: 3} shoes := Item{name: "Sports Shoes", price: 30000, quantity: 2} items := Items{shirt, shoes}

fmt.Println("cost of shirt: ", shirt.Cost()) fmt.Println("cost of shoes: ", shoes.Cost()) fmt.Println("total cost: ", items.Cost())} Run

Go is Object-based

Via custom type and methods

Is Go Object-oriented Language?

What is "Inheritance" (wikipedia)

Provides reuse of existing objects

Classes are created in hierarchies

Inheritance passes knowledge down!

Inheritance is not good

In Java user group meeting, James Gosling (Java’s inventor) says:

You should avoid implementation inheritance whenever possible.

Go's approach

Go avoided inheritance

Go strictly follows the Composition over inheritance principle

What is Composition

Provides reuse of Objects

One object is declared by containing other objects

Composition pulls knowledge into another

Composition in Go

// Type Declarationtype Item struct { name string price float64 quantity int}

type DiscountItem struct { ItemItem discountRate float64}

// In Actionfunc main() { shoes := Item{name: "Sports Shoes", price: 30000, quantity: 2} eventShoes := DiscountItem{eventShoes := DiscountItem{ Item{name: "Women's Walking Shoes", price: 50000, quantity: 3},Item{name: "Women's Walking Shoes", price: 50000, quantity: 3}, 10.00,10.00, }}

fmt.Println("shoes: ", shoes) fmt.Println("eventShoes: ", eventShoes)} Run

Call Method of Embedded Type

type DiscountItem struct { Item discountRate float64}

// Method Declarationfunc (t Item) Cost() float64 {func (t Item) Cost() float64 { return t.price * float64(t.quantity)return t.price * float64(t.quantity)}}

// In Actionfunc main() { shoes := Item{name: "Sports Shoes", price: 30000, quantity: 2} eventShoes := DiscountItem{ Item{name: "Women's Walking Shoes", price: 50000, quantity: 3}, 10.00, }

fmt.Println("cost of shoes: ", shoes.Cost())fmt.Println("cost of shoes: ", shoes.Cost()) fmt.Println("cost of eventShoes: ", eventShoes.Cost())fmt.Println("cost of eventShoes: ", eventShoes.Cost())} Run

Method Overriding

// Method Declarationfunc (t Item) Cost() float64 { return t.price * float64(t.quantity)}

func (t DiscountItem) Cost() float64 {func (t DiscountItem) Cost() float64 { return t.Item.Cost() * (1.0 - t.discountRate/100)return t.Item.Cost() * (1.0 - t.discountRate/100)}}

// In Actionfunc main() { shoes := Item{name: "Sports Shoes", price: 30000, quantity: 2} eventShoes := DiscountItem{ Item{name: "Women's Walking Shoes", price: 50000, quantity: 3}, 10.00, }

fmt.Println("cost of shoes: ", shoes.Cost()) fmt.Println("cost of eventShoes: ", eventShoes.Cost())} Run

Composition in Go 2

// Type Declaration (embedded field)type Order struct { ItemsItems taxRate float64}

// Overriding Methodsfunc (o Order) Cost() float64 {func (o Order) Cost() float64 { return o.Items.Cost() * (1.0 + o.taxRate/100)}

func main() { shirt := Item{name: "Men's Slim-Fit Shirt", price: 25000, quantity: 3} shoes := Item{name: "Sports Shoes", price: 30000, quantity: 2} items := Items{shirt, shoes} order := Order{Items: items, taxRate: 10.00}

fmt.Println("cost of shirt: ", shirt.Cost()) fmt.Println("cost of shoes: ", shoes.Cost()) fmt.Println("total cost: ", items.Cost()) fmt.Println("total cost(included Tax): ", order.Cost())} Run

Composition in Go 3

func main() { shirt := Item{name: "Men's Slim-Fit Shirt", price: 25000, quantity: 3} shoes := Item{name: "Sports Shoes", price: 30000, quantity: 2} eventShoes := DiscountItem{ Item{name: "Women's Walking Shoes", price: 50000, quantity: 3}, 10.00, } items := Items{shirt, shoes, eventShoes} order := Order{Items: items, taxRate: 10.00}

fmt.Println("cost of shirt: ", shirt.Cost()) fmt.Println("cost of shoes: ", shoes.Cost()) fmt.Println("cost of eventShoes: ", eventShoes.Cost()) fmt.Println("total cost: ", items.Cost()) fmt.Println("total cost(included Tax): ", order.Cost())} Run

Composition in Go 4

func main() { shirt := Item{name: "Men's Slim-Fit Shirt", price: 25000, quantity: 3} shoes := Item{name: "Sports Shoes", price: 30000, quantity: 2} eventShoes := DiscountItem{ Item{name: "Women's Walking Shoes", price: 50000, quantity: 3}, 10.00, } items := Items{shirt, shoes, eventShoes} order := Order{Items: items, taxRate: 10.00}

fmt.Println("cost of shirt: ", shirt.Cost()) fmt.Println("cost of shoes: ", shoes.Cost()) fmt.Println("cost of eventShoes: ", eventShoes.Cost()) fmt.Println("total cost: ", items.Cost()) fmt.Println("total cost(included Tax): ", order.Cost())} Run

What is "Polymorphism" (wikipedia)

The provision of a single interface to entities of different types

Via Generics, Overloading and/or Subtyping

Go’s approach

Go avoided subtyping & overloading

Go does not provide Generics

Polymorphism via interfaces

Interfaces in Go

Interfaces are just sets of methods

Interfaces define behavior (duck typing)

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

Interfaces in Go

type Rental struct { name string feePerDay float64 periodLength int RentalPeriod}

type RentalPeriod int

const ( Days RentalPeriod = iota Weeks Months)

func (p RentalPeriod) ToDays() int { switch p { case Weeks: return 7 case Months: return 30 default: return 1 }}

Interfaces in Go

func (r Rental) Cost() float64 { return r.feePerDay * float64(r.ToDays()*r.periodLength)}

// Interface Declarationtype Coster interface {type Coster interface { Cost() float64Cost() float64}}

func DisplayCost(c Coster) {func DisplayCost(c Coster) { fmt.Println("cost: ", c.Cost())}

// In Actionfunc main() { shirt := Item{name: "Men's Slim-Fit Shirt", price: 25000, quantity: 3} video := Rental{"Interstellar", 1000, 3, Days}

fmt.Printf("[%v] ", shirt.name) DisplayCost(shirt)DisplayCost(shirt) fmt.Printf("[%v] ", video.name) DisplayCost(video)DisplayCost(video)} Run

Interfaces in Go 2

// Interface Declarationtype Coster interface { Cost() float64}

// Itemstype Items []Costertype Items []Coster

func main() { shirt := Item{name: "Men's Slim-Fit Shirt", price: 25000, quantity: 3} video := Rental{"Interstellar", 1000, 3, Days} eventShoes := DiscountItem{ Item{name: "Women's Walking Shoes", price: 50000, quantity: 3}, 10.00, } items := Items{shirt, video, eventShoes} order := Order{Items: items, taxRate: 10.00}

DisplayCost(shirt) DisplayCost(video) DisplayCost(eventShoes) DisplayCost(items) DisplayCost(order)}

Run

Satisfying Interface of Other Package

fmt.Println

func Println(a ...interface{}) (n int, err error) { return Fprintln(os.Stdout, a...)}

func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { ... // print using Stringer interface ... return}

fmt.Stringer

type Stringer interface { String() string}

Satisfying Interface of Other Package

// Stringerfunc (t Item) String() string { return fmt.Sprintf("[%s] %.0f", t.name, t.Cost())}

func (t Rental) String() string { return fmt.Sprintf("[%s] %.0f", t.name, t.Cost())}

func (t DiscountItem) String() string { return fmt.Sprintf("%s => %.0f(%.0f%s DC)", t.Item.String(), t.Cost(), t.discountRate, "%")}

func (t Items) String() string { return fmt.Sprintf("%d items. total: %.0f", len(t), t.Cost())}

func (o Order) String() string { return fmt.Sprintf("Include Tax: %.0f(tax rate: %.2f%s)", o.Cost(), o.taxRate, "%")}

Satisfying Interface of Other Package

func main() { shirt := Item{name: "Men's Slim-Fit Shirt", price: 25000, quantity: 3} video := Rental{"Interstellar", 1000, 3, Days} eventShoes := DiscountItem{ Item{name: "Women's Walking Shoes", price: 50000, quantity: 3}, 10.00, } items := Items{shirt, video, eventShoes} order := Order{Items: items, taxRate: 10.00}

fmt.Println(shirt) fmt.Println(video) fmt.Println(eventShoes) fmt.Println(items) fmt.Println(order)} Run

Deep into Go's Standard Library

io.Writer interface

// http://godoc.org/io#Writertype Writer interface { Write(p []byte) (n int, err os.Error)}

fmt.Fprintln function

func Fprintln(w io.Writer, a ...interface{}) (n int, err error)

The Power of Interfaces

In handle function, just write to io.Writer object

func handle(w io.Writer, msg string) { fmt.Fprintln(w, msg)}

The os.Stdout can be used for io.Writer.

func main() { msg := []string{"hello", "world", "this", "is", "an", "example", "of", "io.Writer"} for _, s := range msg { time.Sleep(100 * time.Millisecond) handle(os.Stdout, s)handle(os.Stdout, s) }} Run

The Power of Interfaces

The http.ResponseWriter can be used for io.Writer.

localhost:4000/hello-world (http://localhost:4000/hello-world)

localhost:4000/this-is-an-example-of-io.Writer (http://localhost:4000/this-is-an-example-of-io.Writer)

func handle(w io.Writer, msg string) { fmt.Fprintln(w, msg)}

func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { handle(w, r.URL.Path[1:])handle(w, r.URL.Path[1:]) }) fmt.Println("start listening on port 4000") http.ListenAndServe(":4000", nil)} Run

Go is Object-Oriented

Thank you

장재휴Developer, Purpleworksjaehue@jang.io (mailto:jaehue@jang.io)