I read that one of the Gang of Four has sadly died recently. To me their 
book seems to be part of American technology history and tradition and I’m 
glad to have a copy somewhere.

And, for structs that need stronger encapsulation (private fields, enforce 
> invariants at construction time), Go has its own pattern: the functional 
> option pattern.


I’m not sure how that’s related to encapsulation, but this options problem 
is appearing in the standard library because of cancellation via a context 
var. In the Go 2 proposals I’ve been suggesting another pattern where a 
struct type contains shared pointers and read-only values, is called by 
value instead of by pointer by methods, and has fields that are set in the 
value copies for optional behavior.

I haven’t recognized the functional option pattern before (my takeaway is 
“make use of … in API design”) and I’ll keep it in mind. Maybe it’s a good 
solution to this context problem.

Isn't the visitor pattern just a way to implement type switch in languages 
> that don't implement type switch?


The visitor does double dispatch where the behavior of each type can be 
swapped out. Maybe a type switch into a type switch would be equivalent.

This might be of interest for you: "Evaluating the Go Programming Language 
> with Design Patterns".


I’m seeing overuse of interface, but I’ll read this paper in more detail.

The Wikipedia article on Anti-patterns is interesting: 
https://en.wikipedia.org/wiki/Anti-pattern. I learned what “bike shedding” 
means, and I think that pattern would be better described as “working on 
the bike shed”.

Thanks,
Matt

On Thursday, February 8, 2018 at 9:22:23 AM UTC-6, Joshua Humphries wrote:
>
> On Wed, Feb 7, 2018 at 5:45 PM, roger peppe <rogp...@gmail.com 
> <javascript:>> wrote:
>
>> As someone totally unfamiliar with the GoF patterns, hre's my take.
>> I looked at the wikipedia articles and tried to work out what
>> problem I thought the pattern was trying to address and then
>> wrote some Go code to do that. I'm generally in agreement
>> with those who say that these patterns are there largely to avoid
>> the pitfalls of languages with class-based inheritance.
>>
>
> Some are targeted specifically at C++/Java -- not due to class-based 
> inheritance but to language/syntax limitations. For example the builder 
> pattern is meant to make construction of objects more readable than 
> overloaded constructors/factories with telescoping argument lists. Go has 
> less need for this because of its struct literal syntax. And, for structs 
> that need stronger encapsulation (private fields, enforce invariants at 
> construction time), Go has its own pattern: the functional option pattern 
> <https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis>.
>
> They certainly aren't all there to avoid pitfalls of class-based 
> inheritance. Many are intuitive solutions to certain classes of problems: 
> one could easily write code that adheres to one of these patterns without 
> even realizing it (adapters, facades, decorators, interceptors, commands, 
> strategies, flyweights, iterators, observers, DSLs). Admittedly, some are 
> less powerful/expressive without class-based inheritance, so less 
> applicable to Go. But, as alluded to in the previous paragraph, Go has some 
> of its own patterns.
>
>
>> abstract factory https://play.golang.org/p/syHr7QJ9e2q
>> - anything in Go that returns an interface rather than a concrete type
>> could be considered an abstract factory.
>>
>
> This isn't quite right. Your example is just a parameterized factory 
> method. This pattern is about the factory itself being abstract. Here's a 
> re-worked example: https://play.golang.org/p/joSYzhMeS0n
> This pattern is a specialization of the strategy 
> <https://en.wikipedia.org/wiki/Strategy_pattern> pattern.
>  
>
>>
>> facade https://play.golang.org/p/U6DSg5pDC0w
>> - any type that has another type as a member and not much
>> significant logic in its own methods could be considered a facade.
>>
>
> And if that facade implements a particular interface then it is also an 
> example of the adapter <https://en.wikipedia.org/wiki/Adapter_pattern> 
> pattern. More adapter examples: bytes.NewReader() and strings.NewReader(). 
> They adapt []byte or string to the io.Reader interface.
>  
>
>>
>> proxy https://golang.org/pkg/bufio/#NewReader
>> - any Go function that takes an interface and returns a
>> value that implements the same interface could be considered
>> a proxy.
>>
>
> This describes the decorator pattern more than the proxy pattern. Usually, 
> a proxy isn't just a wrapper (like a decorator is) -- the proxy object is 
> some form of stand-in for some other resource, typically remote. RPC is a 
> much better example of the proxy pattern (like the "net/rpc" package, but 
> also things like gRPC). Sometimes proxies also add functionality (like the 
> decorator pattern), translate protocols (a la the adapter pattern), or 
> perform routing/multiplexing/demultiplexing.
>
> Another related pattern is the interceptor pattern (aka 
> chain-of-responsibility 
> <https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern>).
>  
>
>>
>> factory method: https://play.golang.org/p/AmQ7lQHAPDy
>> - any function or method that creates and returns an object could
>> be considered a factory. Go doesn't have constructors so this
>> is just normal.
>>
>>
> This statement describes "factory method", but is not at all what the 
> factory method pattern is about. This pattern is specific to class-based 
> inheritance. The idea is to create a virtual/abstract factory method that 
> sub-classes override to return different sub-types/implementations.
>
> Since Go does not have class-based inheritance, the closest I could 
> envision is "override" behavior via a function field. Here's a take on it 
> based on the example in the wikipedia page 
> <https://en.wikipedia.org/wiki/Factory_method_pattern>: 
> https://play.golang.org/p/EnZ4sRFdmyT
>
>  
>
>> visitor: https://play.golang.org/p/w74EhhuAhT5
>> - I'm not sure that this is a great pattern. Doing a callback for every
>> object in a hierarchy seems fine, but requiring a different method
>> to be implemented for each kind of object seems unnecessary - if
>> you add another kind of object, then all the code using the visitor
>> will break (but that could also be considered an advantage, I guess,
>> as it means your clients are forced to consider all possible kinds).
>>
>
> This one also is more suited to class-based inheritance as there is 
> usually a base class implementation that has a no-op implementation for all 
> callbacks. That way, the code implementing the visitor is not broken 
> whenever a new method is added to the visitor. (In Go, you could embed a 
> no-op visitor, so that you only need to implement the subset of applicable 
> methods.) For what it's worth, adding other kinds of objects is not a 
> common operation. The kinds of objects are usually a closed enumeration -- 
> think productions in a CFG.
>
> This is most often used for applying recursive algorithms to complex 
> tree-like structures -- typically ASTs. It can be a nice way to organize 
> that kind of code, but I think the pattern loses a good bit of its 
> expressive power without generics (and also loses a little without 
> traditional class-based polymorphism).
>
> So in Go, I think one would just use a normal recursive function with a 
> switch over the kind of input.
>  
>
>> On 6 February 2018 at 23:30,  <matthe...@gmail.com <javascript:>> wrote:
>> >> Your visitor pattern here seems to not be a "visitor" pattern. I would
>> >> think that the Go equivalent would define an interface, and visit 
>> based on
>> >> that interface.
>> >
>> >
>> > Here’s what the Wikipedia article says:
>> >
>> >> In essence, the visitor allows adding new virtual functions to a 
>> family of
>> >> classes, without modifying the classes. Instead, a visitor class is 
>> created
>> >> that implements all of the appropriate specializations of the virtual
>> >> function. The visitor takes the instance reference as input, and 
>> implements
>> >> the goal through double dispatch.
>> >
>> >
>> > In my Go conversion the family of classes is the File type. The virtual
>> > function Accept is added to the family without defining behavior. The
>> > Dispatcher is interchangeable and implements Accept for each type of 
>> File.
>> >
>> > There's a good possibility that I misunderstood the source example, but 
>> I'm
>> > not sure why this isn't a visitor pattern.
>> >
>> >> This isn't really an example of a factory method, because it isn't
>> >> instantiating things of different types.
>> >
>> >
>> > Vars of func types is like a set of classes with only methods. Lately 
>> I've
>> > been looking at func types and closures as a pattern that's superior to
>> > interface in some cases.
>> >
>> >> I didn't look at all your examples, but in most cases, it seems like 
>> error
>> >> handling, which would be an important part of a Go example, is 
>> completely
>> >> absent in the examples given here.
>> >
>> >
>> > Once I dig out the book I’ll try to put together closer to idiomatic
>> > examples.
>> >
>> > Thanks,
>> > Matt
>> >
>> > On Monday, February 5, 2018 at 11:36:42 AM UTC-6, Eric Johnson wrote:
>> >>
>> >> An interesting idea. Some thoughts....
>> >>
>> >> On Friday, February 2, 2018 at 9:03:54 AM UTC-8, matthe...@gmail.com
>> >> wrote:
>> >>>
>> >>> I’m looking at patterns summarized on Wikipedia from “Design Patterns:
>> >>> Elements of Reusable Object-Oriented Software” and writing out a few 
>> as the
>> >>> equivalent in Go.
>> >>>
>> >>> Visitor: https://play.golang.org/p/A5tNzxMmetH
>> >>
>> >>
>> >> Your visitor pattern here seems to not be a "visitor" pattern. I would
>> >> think that the Go equivalent would define an interface, and visit 
>> based on
>> >> that interface.
>> >>
>> >>>
>> >>>
>> >>> Abstract Factory: https://play.golang.org/p/SWwuX49eysd
>> >>>
>> >>> Factory Method: https://play.golang.org/p/FRgDBx2CLFf
>> >>
>> >>
>> >> This isn't really an example of a factory method, because it isn't
>> >> instantiating things of different types.
>> >>
>> >>>
>> >>>
>> >>> Facade: https://play.golang.org/p/forPdwy9VCi
>> >>
>> >>
>> >>>
>> >>>
>> >>> Proxy: https://play.golang.org/p/DFWuDPTOzEP
>> >>>
>> >>> I’m curious how more experienced people rank these and the other
>> >>> patterns.
>> >>
>> >>
>> >> I didn't look at all your examples, but in most cases, it seems like 
>> error
>> >> handling, which would be an important part of a Go example, is 
>> completely
>> >> absent in the examples given here.
>> >>
>> >> Eric
>> >>
>> >>>
>> >>>
>> >>> Matt
>> >
>> > --
>> > You received this message because you are subscribed to the Google 
>> Groups
>> > "golang-nuts" group.
>> > To unsubscribe from this group and stop receiving emails from it, send 
>> an
>> > email to golang-nuts...@googlegroups.com <javascript:>.
>> > For more options, visit https://groups.google.com/d/optout.
>>
>> --
>> You received this message because you are subscribed to the Google Groups 
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to golang-nuts...@googlegroups.com <javascript:>.
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to