Go Object oriented Design

Source: Internet
Author: User
Tags builtin
This is a creation in Article, where the information may have evolved or changed.

Go Hastypes and Valuesrather than classes and objects. So can a language without classes or objects be object-oriented?

While Go could not fit the typical mold of an OOP language, it does provide many of the same features, albeit in a slightly Different:

    • Methodson any typewe define, with no boxing or unboxing

    • Automatic Message delegation viaembedding

    • Polymorphism Viainterfaces

    • Namespacing Viaexports

There is no inheritance on Go, so leave those is-a relationships at the door. To write Go, we need to think on OO design in terms of composition.

"Use of classical inheritance are always optional; Every problem that it solves can be solved another. "-Sandi Metz

Composition by Example

Have recently read through practical object-oriented programming in Ruby, I decided to translate the examples to Go.

Chapter 6 presents a simple problem. A mechanic needs to know which spare parts to bring on a bike trips, depending on which bikes has been rented. The problem can be solved using classical inheritance, where and is MountainBike RoadBike specializations of a Bicycle base class. Chapter 8 Reworks The same example touse composition instead. I ' m quite happy with how well this version translated to Go. Let's take a look.

Packages

Package main import "FMT"

Packages provide a namespace. The function of the package was main() main where a program begins. The package fmt provides string formatting functions.

Types

Type part struct {Name string Description string needsspare bool}

We define a new type named part. This structure was very much like a C struct.

Type Parts []part

The Parts type is a slice of part values. Slices is variable-length arrays, which is more common in Go than their fixed-length brethren.

Methods

We can declare methods on any user-defined type, so Parts can haveall the behavior of slices, plus our own custom behavior .

Func (Parts Parts) spares () (spares parts) {For _, part: = Range Parts {if part. Needsspare {spares = append (spares, part)}} return spares}

A method declaration in Go was just like a function, except it had anexplicit receiver, declared immediately after func . T His function also takes advantage of named return variables, pre-initializing spares for us.

The method body is fairly straightforward. We iterate over parts, ignoring the index position ( _ ) and filtering the parts to return. appendthe builtin need to allocate and return a larger slice, as we didn ' t preallocate its capacity.

This is code isn ' t nearly as elegant as in select Ruby. A functional filter is possible on Go, but it isn ' t builtin.

Embedding

Type Bicycle struct {Size string Parts}

Bicycle is composed of a Size and Parts. By does specifying a named field for Parts, we do use of embedding. This provides automatic delegation with no further ceremony, eg. and is bike.Spares() bike.Parts.Spares() equivalent.

If we were to add a Spares() method to Bicycle, it would take precedence, but we could still reference the embedded Parts.Spares() . This could feel like inheritance, butembedding does not provide polymorphism. The receiver for methods on Parts is always being of type Parts, even when delegated through Bicycle.

Patterns used with classical inheritance, as the template method pattern, aren ' t suitable for embedding. It's far from better to think in terms of composition & delegation, as we had here.

Composite literals

var  (     RoadBikeParts = Parts{          {"Chain",  "10-speed", true},           {"Tire_size",  "",  true},         {"Tape_color",   "Red",  true},     }     mountainbikeparts =  parts{         {"Chain",  "10-speed", true},          {"Tire_size",  "2.1", true},          {"Front_shock",  "Manitou", false},          {"Rear_shock",  "Fox", true},     }      recumbentbikeparts = parts{         {"Chain ", " 9-speed ",  true},         {"Tire_size",  ", true}, "         {"Flag",  "Tall and orange", true},      } )

Go provides a nice syntax for initializing values, called composite literals. Being able to initialize a structs with an array-like syntax made the partsfactory from the Ruby example feel unnecessary.

Func Main () {roadbike: = bicycle{size: "L", parts:roadbikeparts} mountainbike: = bicycle{size: "L", Parts:mount Ainbikeparts} recumbentbike: = bicycle{size: "L", parts:recumbentbikeparts}

Composite literals can also use a field: value syntax with which all fields is optional.

The short Declaration operator ( := ) Usestype Inferenceto Initialize roadbike, etc. with the Bicycle type.

Output

Fmt. Println (Roadbike.spares ()) fmt. Println (Mountainbike.spares ()) fmt. Println (Recumbentbike.spares ())

We print the result of calling spares in the default format:

[{Chain 10-speed true} {tire_size true} {Tape_color red true}] [{Chain 10-speed true} {Tire_size 2.1 true} {Rear_shock Fox true}] [{Chain 9-speed true} {Tire_size to True} {flag tall and orange true}]

Combining Parts

Comboparts: = parts{} comboparts = Append (Comboparts, mountainbike.parts ...)     Comboparts = Append (Comboparts, roadbike.parts ...)     Comboparts = Append (Comboparts, recumbentbike.parts ...) Fmt. Println (Len (comboparts), comboparts[9:]) fmt. Println (Comboparts.spares ())}

Parts behaves like a slice. Getting the length, slicing the slice, or combining multiple slices all works as usual.

It would seem that's the equivalent solution in Ruby are to subclass arrays, but unfortunately Ruby "misplaces" The Spares Me Thod when the Parts is concatenated (Update:steve Klabnik goes into detail).

"... in a perfect object-oriented language this solution would is exactly correct. Unfortunately, the Ruby language have not quite achieved perfection ... "-Sandi Metz

Interfaces

Polymorphism in Go are provided by interfaces. They aresatisfied implicitly, unlike Java or C #, so interfaces can is defined for code we don ' t own.

Compared to Duck Typing,interfaces is statically Checkedand documented through their declaration, rather than through WRI Ting a series of respond_to? tests.

"It is impossible to create a abstraction unknowingly or by accident; In statically typed languages defining an interface are always intentional. "-Sandi Metz

For a simple example, let's say we didn ' t want to print the NEEDSSPARE flag of part. We could write a String method as such:

Func (part) string () string {return FMT. Sprintf ("%s:%s", part.) Name, part. Description)}

Then the calls to Println above would output this instead:

[Chain:10-speed tire_size:23 tape_color:red] [Chain:10-speed tire_size:2.1 Rear_shock:fox] [Chain:9-speed tire_size:28 Flag:tall and Orange]

This works because we has satisfied the Stringer interface, which the package makes use of fmt . It is defined as:

Type Stringer Interface {string () string}

Interface types can be used on the same places as other types. Variables and arguments can take a Stringer, which accepts anything that implements the String() string method signature.

Exports

Go uses packages for namespacing. exported identifiers begin with a capital letter. Identifier internal to a package, we start it with a lowercase letter:

Type part struct {name string description string needsspare bool}

Then we could export setter and getter methods:

Func (part) Name () string {return Part.name} func (part *part) SetName (name string) {Part.name = name}

It's easy-to-determine what's using the public API vs. internal fields or methods. Just look at the case of the identifier (eg. part.Name() vs. part.name ).

Notice that we don ' t prefix getters with Get (eg. GetName ). Getters aren ' t strictly necessary either, especially with strings. When the need arises, we can always change the Name field to use a custom type that satisfies the Stringer interface.

Finding Some Privacy

Internal names ( lowerCase ) can be accessed from anywhere in the same package, even if the package contains multiple structs Across multiple files. If you find this unsettling, packages can also is as small as you need.

It is good practice to use the (more stable) public API when possible, even from within the same class in classic Al languages. Go ' s use of capitalization makes it easy to see where the-is-the case.

For great good

Composition, embedding and interfaces provide powerful tools for object-oriented Design in Go.

While idiomatic go requires a change in thinking, I am pleasantly surprised with how simple and concise Go code can be wh En playing to its strengths.

Comment on go+, Hacker News, Reddit, LinkedIn, or the Go Nuts mailing list.

"So few people realize that classes and inheritance is mostly historic accidents and not real needs for good OOD."-Jav Ier Guerra via go+

"This is excellent stuff. It helps who looks for correspondences at least to get started.  Some people would inevitably look for OO analogies when learning Go [like I did!], but the official docs avoid them like The plague. "-Rodrigo Moraes via go+

"Seconding +rodrigo Moraes here, excellent stuff. I think this would has accelerated my own learning curve, where I ' ve kept looking for classical OO approaches. Thanks for the writeup. "-Levi Cook via go+ and Twitter

"Great article, really enjoyed it! Well structured and example code seems to is good. Would be going over this again tomorrow and adding some of the tricks I wasn ' t aware of to my toolbox. "-Codygman via HN

"This article is great. I come from the Land of C # (and Python, JS) and this really cleared to a lot of questions I had about what OO works in Go. "-Tinygoats via Reddit

"Great post! Having also read Poodr, it's great to see how well Go fares in terms of concise-ness and expressiveness against a LANGUAG E like Ruby. "-Benjamin Moss via LinkedIn

"Yes, indeed, good post"-Alexander Zhaunerchyk via LinkedIn

"Enjoyed this one. Still trying to wrap my head around some of it. "-Sammy Moshe via LinkedIn

"A great introduction to the Go language from @nathany:" Go Object oriented Design "-Pat Shaughnessy via Twitter

"There is a awesome article written by Nathan Youngman which I highly recommend every beginner should read. It really put many details into perspective for me. "-Alejandro Gaviria via Personal ramblings

"Your article is a great introduction to Go. I sure could has  benefited from reading it before throwing myself in! "-Andrew  mackenzie-ross via MACKROSS.N ET

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.