Full Code of tmrts/go-patterns for AI

master f978e4203617 cached
29 files
55.9 KB
14.8k tokens
27 symbols
1 requests
Download .txt
Repository: tmrts/go-patterns
Branch: master
Commit: f978e4203617
Files: 29
Total size: 55.9 KB

Directory structure:
gitextract_krcxlr3l/

├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SUMMARY.md
├── behavioral/
│   ├── observer/
│   │   └── main.go
│   ├── observer.md
│   └── strategy.md
├── book.json
├── concurrency/
│   ├── bounded_parallelism.go
│   ├── bounded_parallelism.md
│   ├── generator.md
│   ├── parallelism.go
│   └── parallelism.md
├── creational/
│   ├── builder.md
│   ├── factory.md
│   ├── object-pool.md
│   └── singleton.md
├── idiom/
│   └── functional-options.md
├── messaging/
│   ├── fan_in.md
│   ├── fan_out.md
│   └── publish_subscribe.md
├── profiling/
│   └── timing.md
├── stability/
│   └── circuit-breaker.md
├── structural/
│   ├── decorator.md
│   ├── proxy/
│   │   └── main.go
│   └── proxy.md
└── synchronization/
    └── semaphore.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.prof
# Test binary, build with `go test -c`
*.test
# Binaries for programs and plugins
*.exe
*.dll
*.dylib

# JetBrains project files
.idea/

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

================================================
FILE: .travis.yml
================================================
language: node_js

env:
  global:
    - GH_REPO="github.com/tmrts/go-patterns"
    - secure: SRAVBGLCkoVpCNC5J43qC6xcQvigIYbGKgLMLiP9B4XiyKH/Q6VGjk/BVVPYuC0d072jNjgfhVdTLx/jGgy6nN+AD7i8U/FoDY6pQmy4cK1nghUUlt44mq7JTlXYHLmV3NsaxmRMV5QuO9L/9AMcCh6U0MxrgMYafSPaSdHQq8hTkFFOYU05zKKUihLF3sVfEZ0KpxhHjtKA+SqcJK2NjqaGdySaziSe6Nj1kZgF9/SJkOiw/bM7O4/uqFXqEGZo5QaOQpwaj2B0wfGqwfJtyE2wM+80Aw5Ya/yqdQWplUozHKv36/u1N45cHkeDbr+RXnBpmUfGh8YTbInWh9BjyU5MLgKeJTtUMAVvwr/soa+OsHuGmdeVM5mRdXISlFSnXCkoowJ6iQsPdqGvYROz0KqqXmkVDuUKdxPU4ShyKo/LqtRwXvxQS9etF4ais8MoNmW0zI3eKdc4b6cpCXWt5fUtK8uzSUGDHHVFGpWnk8VsF0cPfLYxd9bo87amHqYGQoPJ4ughTtOAbA6uSNlcDM9AkQ591+vHpQE15td2VXUOf7aKqqPFWy+GagsI/yPry6v3d/Mk5D4ZLUXZGOv5uvengyos0dxWg9EV1yjm/mpiCtuqAtvV9HMNxcMGGCii7dMy37WmGBj3HBqeGPYHvt8pKMo2/gkcXxadzBXvJVs=

install:
  - npm install gitbook-cli
  - gitbook install

script:
  - gitbook build . out

after_success:
  - echo -e "Deploying updates to GitHub..."
  - MSG=$(git log -1 --oneline)
  - cd out
  - git config --global user.email "contact@tmrts.com"
  - git config --global user.name "Tamer Tas"
  - git init
  - git checkout -b gh-pages
  - git add -A :/
  - git commit -m "Travis CI | ${MSG}"
  - git push "https://${GH_TOKEN}@${GH_REPO}" gh-pages -f


================================================
FILE: CONTRIBUTING.md
================================================
# Contribution Guidelines

Please ensure your pull request adheres to the following guidelines:

- Make an individual pull request for each suggestion.
- Choose the corresponding patterns section for your suggestion.
- List, after your addition, should be in lexicographical order.

## Commit Messages Guidelines

- The message should be in imperative form and uncapitalized.
- If possible, please include an explanation in the commit message body
- Use the form `<pattern-section>/<pattern-name>: <message>` (e.g. `creational/singleton: refactor singleton constructor`)

## Pattern Template

Each pattern should have a single markdown file containing the important part of the implementation, the usage and the explanations for it. This is to ensure that the reader doesn't have to read bunch of boilerplate to understand what's going on and the code is as simple as possible and not simpler.

Please use the following template for adding new patterns:

```markdown
# <Pattern-Name>
<Pattern description>

## Implementation

## Usage

// Optional
## Rules of Thumb 
```


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS


================================================
FILE: README.md
================================================
<p align="center">
  <img src="/gopher.png" height="400">
  <h1 align="center">
    Go Patterns
    <br>
    <a href="http://travis-ci.org/tmrts/go-patterns"><img alt="build-status" src="https://img.shields.io/badge/build-passing-brightgreen.svg?style=flat-square" /></a>
    <a href="https://github.com/sindresorhus/awesome" ><img alt="awesome" src="https://img.shields.io/badge/awesome-%E2%9C%93-ff69b4.svg?style=flat-square" /></a>
    <a href="https://github.com/tmrts/go-patterns/blob/master/LICENSE" ><img alt="license" src="https://img.shields.io/badge/license-Apache%20License%202.0-E91E63.svg?style=flat-square" /></a>
  </h1>
</p>

A curated collection of idiomatic design & application patterns for Go language.

## Creational Patterns

| Pattern | Description | Status |
|:-------:|:----------- |:------:|
| [Abstract Factory](/creational/abstract_factory.md) | Provides an interface for creating families of releated objects | ✘ |
| [Builder](/creational/builder.md) | Builds a complex object using simple objects | ✔ |
| [Factory Method](/creational/factory.md) | Defers instantiation of an object to a specialized function for creating instances | ✔ |
| [Object Pool](/creational/object-pool.md) | Instantiates and maintains a group of objects instances of the same type | ✔ |
| [Singleton](/creational/singleton.md) | Restricts instantiation of a type to one object | ✔ |

## Structural Patterns

| Pattern | Description | Status |
|:-------:|:----------- |:------:|
| [Bridge](/structural/bridge.md) | Decouples an interface from its implementation so that the two can vary independently | ✘ |
| [Composite](/structural/composite.md) | Encapsulates and provides access to a number of different objects | ✘ |
| [Decorator](/structural/decorator.md) | Adds behavior to an object, statically or dynamically | ✔ |
| [Facade](/structural/facade.md) | Uses one type as an API to a number of others | ✘ |
| [Flyweight](/structural/flyweight.md) | Reuses existing instances of objects with similar/identical state to minimize resource usage | ✘ |
| [Proxy](/structural/proxy.md) | Provides a surrogate for an object to control it's actions | ✔ |

## Behavioral Patterns

| Pattern | Description | Status |
|:-------:|:----------- |:------:|
| [Chain of Responsibility](/behavioral/chain_of_responsibility.md) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | ✘ |
| [Command](/behavioral/command.md) | Bundles a command and arguments to call later | ✘ |
| [Mediator](/behavioral/mediator.md) | Connects objects and acts as a proxy | ✘ |
| [Memento](/behavioral/memento.md) | Generate an opaque token that can be used to go back to a previous state | ✘ |
| [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | ✔ |
| [Registry](/behavioral/registry.md) | Keep track of all subclasses of a given class | ✘ |
| [State](/behavioral/state.md) | Encapsulates varying behavior for the same object based on its internal state | ✘ |
| [Strategy](/behavioral/strategy.md) | Enables an algorithm's behavior to be selected at runtime | ✔ |
| [Template](/behavioral/template.md) | Defines a skeleton class which defers some methods to subclasses | ✘ |
| [Visitor](/behavioral/visitor.md) | Separates an algorithm from an object on which it operates | ✘ |

## Synchronization Patterns

| Pattern | Description | Status |
|:-------:|:----------- |:------:|
| [Condition Variable](/synchronization/condition_variable.md) | Provides a mechanism for threads to temporarily give up access in order to wait for some condition | ✘ |
| [Lock/Mutex](/synchronization/mutex.md) | Enforces mutual exclusion limit on a resource to gain exclusive access | ✘ |
| [Monitor](/synchronization/monitor.md) | Combination of mutex and condition variable patterns | ✘ |
| [Read-Write Lock](/synchronization/read_write_lock.md) | Allows parallel read access, but only exclusive access on write operations to a resource | ✘ |
| [Semaphore](/synchronization/semaphore.md) | Allows controlling access to a common resource | ✔ |

## Concurrency Patterns

| Pattern | Description | Status |
|:-------:|:----------- |:------:|
| [N-Barrier](/concurrency/barrier.md) | Prevents a process from proceeding until all N processes reach to the barrier | ✘ |
| [Bounded Parallelism](/concurrency/bounded_parallelism.md) | Completes large number of independent tasks with resource limits | ✔ |
| [Broadcast](/concurrency/broadcast.md) | Transfers a message to all recipients simultaneously | ✘ |
| [Coroutines](/concurrency/coroutine.md) | Subroutines that allow suspending and resuming execution at certain locations | ✘ |
| [Generators](/concurrency/generator.md) | Yields a sequence of values one at a time | ✔ |
| [Reactor](/concurrency/reactor.md) | Demultiplexes service requests delivered concurrently to a service handler and dispatches them syncronously to the associated request handlers | ✘ |
| [Parallelism](/concurrency/parallelism.md) | Completes large number of independent tasks | ✔ |
| [Producer Consumer](/concurrency/producer_consumer.md) | Separates tasks from task executions | ✘ |

## Messaging Patterns

| Pattern | Description | Status |
|:-------:|:----------- |:------:|
| [Fan-In](/messaging/fan_in.md) | Funnels tasks to a work sink (e.g. server) | ✔ |
| [Fan-Out](/messaging/fan_out.md) | Distributes tasks among workers (e.g. producer) | ✔ |
| [Futures & Promises](/messaging/futures_promises.md) | Acts as a place-holder of a result that is initially unknown for synchronization purposes | ✘ |
| [Publish/Subscribe](/messaging/publish_subscribe.md) | Passes information to a collection of recipients who subscribed to a topic | ✔ |
| [Push & Pull](/messaging/push_pull.md) | Distributes messages to multiple workers, arranged in a pipeline | ✘ |

## Stability Patterns

| Pattern | Description | Status |
|:-------:|:----------- |:------:|
| [Bulkheads](/stability/bulkhead.md)  | Enforces a principle of failure containment (i.e. prevents cascading failures) | ✘ |
| [Circuit-Breaker](/stability/circuit-breaker.md) | Stops the flow of the requests when requests are likely to fail | ✔ |
| [Deadline](/stability/deadline.md) | Allows clients to stop waiting for a response once the probability of response becomes low (e.g. after waiting 10 seconds for a page refresh) | ✘ |
| [Fail-Fast](/stability/fail_fast.md) | Checks the availability of required resources at the start of a request and fails if the requirements are not satisfied | ✘ |
| [Handshaking](/stability/handshaking.md) | Asks a component if it can take any more load, if it can't, the request is declined | ✘ |
| [Steady-State](/stability/steady_state.md) | For every service that accumulates a resource, some other service must recycle that resource | ✘ |

## Profiling Patterns

| Pattern | Description | Status |
|:-------:|:----------- |:------:|
| [Timing Functions](/profiling/timing.md) | Wraps a function and logs the execution | ✔ |

## Idioms

| Pattern | Description | Status |
|:-------:|:----------- |:------:|
| [Functional Options](/idiom/functional-options.md) | Allows creating clean APIs with sane defaults and idiomatic overrides | ✔ |

## Anti-Patterns

| Pattern | Description | Status |
|:-------:|:----------- |:------:|
| [Cascading Failures](/anti-patterns/cascading_failures.md) | A failure in a system of interconnected parts in which the failure of a part causes a domino effect | ✘ |


================================================
FILE: SUMMARY.md
================================================
# Summary

* [Go Patterns](/README.md)
  * [Creational Patterns](/README.md#creational-patterns)
    * [Abstract Factory](/creational/abstract_factory.md)
    * [Builder](/creational/builder.md)
    * [Factory Method](/creational/factory.md)
    * [Object Pool](/creational/object-pool.md)
    * [Singleton](/creational/singleton.md)
  * [Structural Patterns](/README.md#structural-patterns)
    * [Bridge](/structural/bridge.md)
    * [Composite](/structural/composite.md)
    * [Decorator](/structural/decorator.md)
    * [Facade](/structural/facade.md)
    * [Flyweight](/structural/flyweight.md)
    * [Proxy](/structural/proxy.md)
  * [Behavioral Patterns](/README.md#behavioral-patterns)
    * [Chain of Responsibility](/behavioral/chain_of_responsibility.md)
    * [Command](/behavioral/command.md)
    * [Mediator](/behavioral/mediator.md)
    * [Memento](/behavioral/memento.md)
    * [Observer](/behavioral/observer.md)
    * [Registry](/behavioral/registry.md)
    * [State](/behavioral/state.md)
    * [Strategy](/behavioral/strategy.md)
    * [Template](/behavioral/template.md)
    * [Visitor](/behavioral/visitor.md)
  * [Synchronization Patterns](/README.md#synchronization-patterns)
    * [Condition Variable](/synchronization/condition_variable.md)
    * [Lock/Mutex](/synchronization/mutex.md)
    * [Monitor](/synchronization/monitor.md)
    * [Read-Write Lock](/synchronization/read_write_lock.md)
    * [Semaphore](/synchronization/semaphore.md)
  * [Concurrency Patterns](/README.md#concurrency-patterns)
    * [N-Barrier](/concurrency/barrier.md)
    * [Bounded Parallelism](/concurrency/bounded_parallelism.md)
    * [Broadcast](/concurrency/broadcast.md)
    * [Coroutines](/concurrency/coroutine.md)
    * [Generators](/concurrency/generator.md)
    * [Reactor](/concurrency/reactor.md)
    * [Parallelism](/concurrency/parallelism.md)
    * [Producer Consumer](/concurrency/producer_consumer.md)
  * [Messaging Patterns](/README.md#messaging-patterns)
    * [Fan-In](/messaging/fan_in.md)
    * [Fan-Out](/messaging/fan_out.md)
    * [Futures & Promises](/messaging/futures_promises.md)
    * [Publish/Subscribe](/messaging/publish_subscribe.md)
    * [Push & Pull](/messaging/push_pull.md)
  * [Stability Patterns](/README.md#stability-patterns)
    * [Bulkheads](/stability/bulkhead.md)
    * [Circuit-Breaker](/stability/circuit-breaker.md)
    * [Deadline](/stability/deadline.md)
    * [Fail-Fast](/stability/fail_fast.md)
    * [Handshaking](/stability/handshaking.md)
    * [Steady-State](/stability/steady_state.md)
  * [Profiling Patterns](/README.md#profiling-patterns)
    * [Timing Functions](/profiling/timing.md)
  * [Idioms](/README.md#idioms)
    * [Functional Options](/idiom/functional-options.md)
  * [Anti-Patterns](/README.md#anti-patterns)
    * [Cascading Failures](/anti-patterns/cascading_failures.md)
* [Contributing](/CONTRIBUTING.md)


================================================
FILE: behavioral/observer/main.go
================================================
// Package main serves as an example application that makes use of the observer pattern.
// Playground: https://play.golang.org/p/cr8jEmDmw0
package main

import (
	"fmt"
	"time"
)

type (
	// Event defines an indication of a point-in-time occurrence.
	Event struct {
		// Data in this case is a simple int, but the actual
		// implementation would depend on the application.
		Data int64
	}

	// Observer defines a standard interface for instances that wish to list for
	// the occurrence of a specific event.
	Observer interface {
		// OnNotify allows an event to be "published" to interface implementations.
		// In the "real world", error handling would likely be implemented.
		OnNotify(Event)
	}

	// Notifier is the instance being observed. Publisher is perhaps another decent
	// name, but naming things is hard.
	Notifier interface {
		// Register allows an instance to register itself to listen/observe
		// events.
		Register(Observer)
		// Deregister allows an instance to remove itself from the collection
		// of observers/listeners.
		Deregister(Observer)
		// Notify publishes new events to listeners. The method is not
		// absolutely necessary, as each implementation could define this itself
		// without losing functionality.
		Notify(Event)
	}
)

type (
	eventObserver struct{
		id int
	}

	eventNotifier struct{
		// Using a map with an empty struct allows us to keep the observers
		// unique while still keeping memory usage relatively low.
		observers map[Observer]struct{}
	}
)

func (o *eventObserver) OnNotify(e Event) {
	fmt.Printf("*** Observer %d received: %d\n", o.id, e.Data)
}

func (o *eventNotifier) Register(l Observer) {
	o.observers[l] = struct{}{}
}

func (o *eventNotifier) Deregister(l Observer) {
	delete(o.observers, l)
}

func (p *eventNotifier) Notify(e Event) {
	for o := range p.observers {
		o.OnNotify(e)
	}
}

func main() {
	// Initialize a new Notifier.
	n := eventNotifier{
		observers: map[Observer]struct{}{},
	}

	// Register a couple of observers.
	n.Register(&eventObserver{id: 1})
	n.Register(&eventObserver{id: 2})

	// A simple loop publishing the current Unix timestamp to observers.
	stop := time.NewTimer(10 * time.Second).C
	tick := time.NewTicker(time.Second).C
	for {
		select {
		case <- stop:
			return
		case t := <-tick:
			n.Notify(Event{Data: t.UnixNano()})
		}
	}
}

================================================
FILE: behavioral/observer.md
================================================
# Observer Pattern

The [observer pattern](https://en.wikipedia.org/wiki/Observer_pattern) allows a type instance to "publish" events to other type instances ("observers") who wish to be updated when a particular event occurs.

## Implementation

In long-running applications&mdash;such as webservers&mdash;instances can keep a collection of observers that will receive notification of triggered events.

Implementations vary, but interfaces can be used to make standard observers and notifiers:

```go
type (
	// Event defines an indication of a point-in-time occurrence.
	Event struct {
		// Data in this case is a simple int, but the actual
		// implementation would depend on the application.
		Data int64
	}

	// Observer defines a standard interface for instances that wish to list for
	// the occurrence of a specific event.
	Observer interface {
		// OnNotify allows an event to be "published" to interface implementations.
		// In the "real world", error handling would likely be implemented.
		OnNotify(Event)
	}

	// Notifier is the instance being observed. Publisher is perhaps another decent
	// name, but naming things is hard.
	Notifier interface {
		// Register allows an instance to register itself to listen/observe
		// events.
		Register(Observer)
		// Deregister allows an instance to remove itself from the collection
		// of observers/listeners.
		Deregister(Observer)
		// Notify publishes new events to listeners. The method is not
		// absolutely necessary, as each implementation could define this itself
		// without losing functionality.
		Notify(Event)
	}
)
```

## Usage

For usage, see [observer/main.go](observer/main.go) or [view in the Playground](https://play.golang.org/p/cr8jEmDmw0).


================================================
FILE: behavioral/strategy.md
================================================
# Strategy Pattern
Strategy behavioral design pattern enables an algorithm's behavior to be selected at runtime.

It defines algorithms, encapsulates them, and uses them interchangeably.

## Implementation
Implementation of an interchangeable operator object that operates on integers.

```go
type Operator interface {
	Apply(int, int) int
}

type Operation struct {
	Operator Operator
}

func (o *Operation) Operate(leftValue, rightValue int) int {
	return o.Operator.Apply(leftValue, rightValue)
}
```

## Usage
### Addition Operator
```go
type Addition struct{}

func (Addition) Apply(lval, rval int) int {
	return lval + rval
}
```

```go
add := Operation{Addition{}}
add.Operate(3, 5) // 8
```

### Multiplication Operator
```go
type Multiplication struct{}

func (Multiplication) Apply(lval, rval int) int {
	return lval * rval
}
```

```go
mult := Operation{Multiplication{}}

mult.Operate(3, 5) // 15
```

## Rules of Thumb
- Strategy pattern is similar to Template pattern except in its granularity.
- Strategy pattern lets you change the guts of an object. Decorator pattern lets you change the skin.


================================================
FILE: book.json
================================================
{
    "plugins": [
        "-search", 
        "-lunr",
        "github",
        "edit-link"
    ],
    "pluginsConfig": {
        "github": {
            "url": "https://github.com/tmrts/go-patterns"
        },
        "edit-link": {
            "base": "https://github.com/tmrts/go-patterns/edit/master/",
            "label": ""
        }
    }
}


================================================
FILE: concurrency/bounded_parallelism.go
================================================
package bounded_parallelism

import (
	"crypto/md5"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"sync"
)

// walkFiles starts a goroutine to walk the directory tree at root and send the
// path of each regular file on the string channel.  It sends the result of the
// walk on the error channel.  If done is closed, walkFiles abandons its work.
func walkFiles(done <-chan struct{}, root string) (<-chan string, <-chan error) {
	paths := make(chan string)
	errc := make(chan error, 1)
	go func() { // HL
		// Close the paths channel after Walk returns.
		defer close(paths) // HL
		// No select needed for this send, since errc is buffered.
		errc <- filepath.Walk(root, func(path string, info os.FileInfo, err error) error { // HL
			if err != nil {
				return err
			}
			if !info.Mode().IsRegular() {
				return nil
			}
			select {
			case paths <- path: // HL
			case <-done: // HL
				return errors.New("walk canceled")
			}
			return nil
		})
	}()
	return paths, errc
}

// A result is the product of reading and summing a file using MD5.
type result struct {
	path string
	sum  [md5.Size]byte
	err  error
}

// digester reads path names from paths and sends digests of the corresponding
// files on c until either paths or done is closed.
func digester(done <-chan struct{}, paths <-chan string, c chan<- result) {
	for path := range paths { // HLpaths
		data, err := ioutil.ReadFile(path)
		select {
		case c <- result{path, md5.Sum(data), err}:
		case <-done:
			return
		}
	}
}

// MD5All reads all the files in the file tree rooted at root and returns a map
// from file path to the MD5 sum of the file's contents.  If the directory walk
// fails or any read operation fails, MD5All returns an error.  In that case,
// MD5All does not wait for inflight read operations to complete.
func MD5All(root string) (map[string][md5.Size]byte, error) {
	// MD5All closes the done channel when it returns; it may do so before
	// receiving all the values from c and errc.
	done := make(chan struct{})
	defer close(done)

	paths, errc := walkFiles(done, root)

	// Start a fixed number of goroutines to read and digest files.
	c := make(chan result) // HLc
	var wg sync.WaitGroup
	const numDigesters = 20
	wg.Add(numDigesters)
	for i := 0; i < numDigesters; i++ {
		go func() {
			digester(done, paths, c) // HLc
			wg.Done()
		}()
	}
	go func() {
		wg.Wait()
		close(c) // HLc
	}()
	// End of pipeline. OMIT

	m := make(map[string][md5.Size]byte)
	for r := range c {
		if r.err != nil {
			return nil, r.err
		}
		m[r.path] = r.sum
	}
	// Check whether the Walk failed.
	if err := <-errc; err != nil { // HLerrc
		return nil, err
	}
	return m, nil
}

func main() {
	// Calculate the MD5 sum of all files under the specified directory,
	// then print the results sorted by path name.
	m, err := MD5All(os.Args[1])
	if err != nil {
		fmt.Println(err)
		return
	}
	var paths []string
	for path := range m {
		paths = append(paths, path)
	}
	sort.Strings(paths)
	for _, path := range paths {
		fmt.Printf("%x  %s\n", m[path], path)
	}
}


================================================
FILE: concurrency/bounded_parallelism.md
================================================
# Bounded Parallelism Pattern

[Bounded parallelism](https://blog.golang.org/pipelines#TOC_9.) is similar to [parallelism](parallelism.md), but allows limits to be placed on allocation.

# Implementation and Example

An example showing implementation and usage can be found in [bounded_parallelism.go](bounded_parallelism.go).

================================================
FILE: concurrency/generator.md
================================================
# Generator Pattern

[Generators](https://en.wikipedia.org/wiki/Generator_(computer_programming)) yields a sequence of values one at a time.

## Implementation 

```go
func Count(start int, end int) chan int {
    ch := make(chan int)

    go func(ch chan int) {
        for i := start; i <= end ; i++ {
            // Blocks on the operation
            ch <- i
        }

		close(ch)
	}(ch)

	return ch
}
```

## Usage

```go
fmt.Println("No bottles of beer on the wall")

for i := range Count(1, 99) {
    fmt.Println("Pass it around, put one up,", i, "bottles of beer on the wall")
    // Pass it around, put one up, 1 bottles of beer on the wall
    // Pass it around, put one up, 2 bottles of beer on the wall
    // ...
    // Pass it around, put one up, 99 bottles of beer on the wall
}

fmt.Println(100, "bottles of beer on the wall")
```


================================================
FILE: concurrency/parallelism.go
================================================
package parallelism

import (
	"crypto/md5"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"sync"
)

// A result is the product of reading and summing a file using MD5.
type result struct {
	path string
	sum  [md5.Size]byte
	err  error
}

// sumFiles starts goroutines to walk the directory tree at root and digest each
// regular file.  These goroutines send the results of the digests on the result
// channel and send the result of the walk on the error channel.  If done is
// closed, sumFiles abandons its work.
func sumFiles(done <-chan struct{}, root string) (<-chan result, <-chan error) {
	// For each regular file, start a goroutine that sums the file and sends
	// the result on c.  Send the result of the walk on errc.
	c := make(chan result)
	errc := make(chan error, 1)
	go func() { // HL
		var wg sync.WaitGroup
		err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if !info.Mode().IsRegular() {
				return nil
			}
			wg.Add(1)
			go func() { // HL
				data, err := ioutil.ReadFile(path)
				select {
				case c <- result{path, md5.Sum(data), err}: // HL
				case <-done: // HL
				}
				wg.Done()
			}()
			// Abort the walk if done is closed.
			select {
			case <-done: // HL
				return errors.New("walk canceled")
			default:
				return nil
			}
		})
		// Walk has returned, so all calls to wg.Add are done.  Start a
		// goroutine to close c once all the sends are done.
		go func() { // HL
			wg.Wait()
			close(c) // HL
		}()
		// No select needed here, since errc is buffered.
		errc <- err // HL
	}()
	return c, errc
}

// MD5All reads all the files in the file tree rooted at root and returns a map
// from file path to the MD5 sum of the file's contents.  If the directory walk
// fails or any read operation fails, MD5All returns an error.  In that case,
// MD5All does not wait for inflight read operations to complete.
func MD5All(root string) (map[string][md5.Size]byte, error) {
	// MD5All closes the done channel when it returns; it may do so before
	// receiving all the values from c and errc.
	done := make(chan struct{}) // HLdone
	defer close(done)           // HLdone

	c, errc := sumFiles(done, root) // HLdone

	m := make(map[string][md5.Size]byte)
	for r := range c { // HLrange
		if r.err != nil {
			return nil, r.err
		}
		m[r.path] = r.sum
	}
	if err := <-errc; err != nil {
		return nil, err
	}
	return m, nil
}

func main() {
	// Calculate the MD5 sum of all files under the specified directory,
	// then print the results sorted by path name.
	m, err := MD5All(os.Args[1])
	if err != nil {
		fmt.Println(err)
		return
	}
	var paths []string
	for path := range m {
		paths = append(paths, path)
	}
	sort.Strings(paths)
	for _, path := range paths {
		fmt.Printf("%x  %s\n", m[path], path)
	}
}


================================================
FILE: concurrency/parallelism.md
================================================
# Parallelism Pattern

[Parallelism](https://blog.golang.org/pipelines#TOC_8.) allows multiple "jobs" or tasks to be run concurrently and asynchronously.

# Implementation and Example

An example showing implementation and usage can be found in [parallelism.go](parallelism.go).

================================================
FILE: creational/builder.md
================================================
# Builder Pattern

Builder pattern separates the construction of a complex object from its
representation so that the same construction process can create different
representations.

In Go, normally a configuration struct is used to achieve the same behavior,
however passing a struct to the builder method fills the code with boilerplate
`if cfg.Field != nil {...}` checks.

## Implementation

```go
package car

type Speed float64

const (
    MPH Speed = 1
    KPH       = 1.60934
)

type Color string

const (
    BlueColor  Color = "blue"
    GreenColor       = "green"
    RedColor         = "red"
)

type Wheels string

const (
    SportsWheels Wheels = "sports"
    SteelWheels         = "steel"
)

type Builder interface {
    Color(Color) Builder
    Wheels(Wheels) Builder
    TopSpeed(Speed) Builder
    Build() Interface
}

type Interface interface {
    Drive() error
    Stop() error
}
```

## Usage

```go
assembly := car.NewBuilder().Paint(car.RedColor)

familyCar := assembly.Wheels(car.SportsWheels).TopSpeed(50 * car.MPH).Build()
familyCar.Drive()

sportsCar := assembly.Wheels(car.SteelWheels).TopSpeed(150 * car.MPH).Build()
sportsCar.Drive()
```


================================================
FILE: creational/factory.md
================================================
# Factory Method Pattern

Factory method creational design pattern allows creating objects without having
to specify the exact type of the object that will be created.

## Implementation

The example implementation shows how to provide a data store with different
backends such as in-memory, disk storage.

### Types

```go
package data

import "io"

type Store interface {
    Open(string) (io.ReadWriteCloser, error)
}
```

### Different Implementations

```go
package data

type StorageType int

const (
    DiskStorage StorageType = 1 << iota
    TempStorage
    MemoryStorage
)

func NewStore(t StorageType) Store {
    switch t {
    case MemoryStorage:
        return newMemoryStorage( /*...*/ )
    case DiskStorage:
        return newDiskStorage( /*...*/ )
    default:
        return newTempStorage( /*...*/ )
    }
}
```

## Usage

With the factory method, the user can specify the type of storage they want.

```go
s, _ := data.NewStore(data.MemoryStorage)
f, _ := s.Open("file")

n, _ := f.Write([]byte("data"))
defer f.Close()
```


================================================
FILE: creational/object-pool.md
================================================
# Object Pool Pattern

The object pool creational design pattern is used to prepare and keep multiple
instances according to the demand expectation.

## Implementation

```go
package pool

type Pool chan *Object

func New(total int) *Pool {
	p := make(Pool, total)

	for i := 0; i < total; i++ {
		p <- new(Object)
	}

	return &p
}
```

## Usage

Given below is a simple lifecycle example on an object pool.

```go
p := pool.New(2)

select {
case obj := <-p:
	obj.Do( /*...*/ )

	p <- obj
default:
	// No more objects left — retry later or fail
	return
}
```

## Rules of Thumb

- Object pool pattern is useful in cases where object initialization is more
  expensive than the object maintenance.
- If there are spikes in demand as opposed to a steady demand, the maintenance
  overhead might overweigh the benefits of an object pool.
- It has positive effects on performance due to objects being initialized beforehand.


================================================
FILE: creational/singleton.md
================================================
# Singleton Pattern

Singleton creational design pattern restricts the instantiation of a type to a single object.

## Implementation

```go
package singleton

type singleton map[string]string

var (
    once sync.Once

    instance singleton
)

func New() singleton {
	once.Do(func() {
		instance = make(singleton)
	})

	return instance
}
```

## Usage

```go
s := singleton.New()

s["this"] = "that"

s2 := singleton.New()

fmt.Println("This is ", s2["this"])
// This is that
```

## Rules of Thumb

- Singleton pattern represents a global state and most of the time reduces testability.


================================================
FILE: idiom/functional-options.md
================================================
# Functional Options

Functional options are a method of implementing clean/eloquent APIs in Go.
Options implemented as a function set the state of that option.

## Implementation

### Options

```go
package file

type Options struct {
	UID         int
	GID         int
	Flags       int
	Contents    string
	Permissions os.FileMode
}

type Option func(*Options)

func UID(userID int) Option {
	return func(args *Options) {
		args.UID = userID
	}
}

func GID(groupID int) Option {
	return func(args *Options) {
		args.GID = groupID
	}
}

func Contents(c string) Option {
	return func(args *Options) {
		args.Contents = c
	}
}

func Permissions(perms os.FileMode) Option {
	return func(args *Options) {
		args.Permissions = perms
	}
}
```

### Constructor

```go
package file

func New(filepath string, setters ...Option) error {
	// Default Options
	args := &Options{
		UID:         os.Getuid(),
		GID:         os.Getgid(),
		Contents:    "",
		Permissions: 0666,
		Flags:       os.O_CREATE | os.O_EXCL | os.O_WRONLY,
	}

	for _, setter := range setters {
		setter(args)
	}

	f, err := os.OpenFile(filepath, args.Flags, args.Permissions)
	if err != nil {
		return err
	} else {
		defer f.Close()
	}

	if _, err := f.WriteString(args.Contents); err != nil {
		return err
	}

	return f.Chown(args.UID, args.GID)
}
```

## Usage

```go
emptyFile, err := file.New("/tmp/empty.txt")
if err != nil {
    panic(err)
}

fillerFile, err := file.New("/tmp/file.txt", file.UID(1000), file.Contents("Lorem Ipsum Dolor Amet"))
if err != nil {
    panic(err)
}
```


================================================
FILE: messaging/fan_in.md
================================================
Fan-In Messaging Patterns
===================================
Fan-In is a messaging pattern used to create a funnel for work amongst workers (clients: source, server: destination).

We can model fan-in using the Go channels.

```go
// Merge different channels in one channel
func Merge(cs ...<-chan int) <-chan int {
	var wg sync.WaitGroup

	out := make(chan int)

	// Start an send goroutine for each input channel in cs. send
	// copies values from c to out until c is closed, then calls wg.Done.
	send := func(c <-chan int) {
		for n := range c {
			out <- n
		}
		wg.Done()
	}

	wg.Add(len(cs))
	for _, c := range cs {
		go send(c)
	}

	// Start a goroutine to close out once all the send goroutines are
	// done.  This must start after the wg.Add call.
	go func() {
		wg.Wait()
		close(out)
	}()
	return out
}
```

The `Merge` function converts a list of channels to a single channel by starting a goroutine for each inbound channel that copies the values to the sole outbound channel.

Once all the output goroutines have been started, `Merge` a goroutine is started to close the main channel.


================================================
FILE: messaging/fan_out.md
================================================
Fan-Out Messaging Pattern
=========================
Fan-Out is a messaging pattern used for distributing work amongst workers (producer: source, consumers: destination).

We can model fan-out using the Go channels.

```go
// Split a channel into n channels that receive messages in a round-robin fashion.
func Split(ch <-chan int, n int) []<-chan int {
	cs := make([]chan int)
	for i := 0; i < n; i++ {
		cs = append(cs, make(chan int))
	}

	// Distributes the work in a round robin fashion among the stated number
	// of channels until the main channel has been closed. In that case, close
	// all channels and return.
	distributeToChannels := func(ch <-chan int, cs []chan<- int) {
		// Close every channel when the execution ends.
		defer func(cs []chan<- int) {
			for _, c := range cs {
				close(c)
			}
		}(cs)

		for {
			for _, c := range cs {
				select {
				case val, ok := <-ch:
					if !ok {
						return
					}

					c <- val
				}
			}
		}
	}

	go distributeToChannels(ch, cs)

	return cs
}
```

The `Split` function converts a single channel into a list of channels by using 
a goroutine to copy received values to channels in the list in a round-robin fashion.


================================================
FILE: messaging/publish_subscribe.md
================================================
Publish & Subscribe Messaging Pattern
============
Publish-Subscribe is a messaging pattern used to communicate messages between 
different components without these components knowing anything about each other's identity.

It is similar to the Observer behavioral design pattern. 
The fundamental design principals of both Observer and Publish-Subscribe is the decoupling of
those interested in being informed about `Event Messages` from the informer (Observers or Publishers).
Meaning that you don't have to program the messages to be sent directly to specific receivers.

To accomplish this, an intermediary, called a "message broker" or "event bus", 
receives published messages, and then routes them on to subscribers.


There are three components **messages**, **topics**, **users**.

```go
type Message struct {
    // Contents
}


type Subscription struct {
	ch chan<- Message

	Inbox chan Message
}

func (s *Subscription) Publish(msg Message) error {
	if _, ok := <-s.ch; !ok {
		return errors.New("Topic has been closed")
	}

	s.ch <- msg

	return nil
}
```

```go
type Topic struct {
	Subscribers    []Session
	MessageHistory []Message
}

func (t *Topic) Subscribe(uid uint64) (Subscription, error) {
    // Get session and create one if it's the first

    // Add session to the Topic & MessageHistory

    // Create a subscription
}

func (t *Topic) Unsubscribe(Subscription) error {
	// Implementation
}

func (t *Topic) Delete() error {
	// Implementation
}
```

```go
type User struct {
    ID uint64
    Name string
}

type Session struct {
    User User
    Timestamp time.Time
}
```

Improvements
============
Events can be published in a parallel fashion by utilizing stackless goroutines.

Performance can be improved by dealing with straggler subscribers
by using a buffered inbox and you stop sending events once the inbox is full.


================================================
FILE: profiling/timing.md
================================================
# Timing Functions

When optimizing code, sometimes a quick and dirty time measurement is required
as opposed to utilizing profiler tools/frameworks to validate assumptions.

Time measurements can be performed by utilizing `time` package and `defer` statements.

## Implementation

```go
package profile

import (
    "time"
    "log"
)

func Duration(invocation time.Time, name string) {
    elapsed := time.Since(invocation)

    log.Printf("%s lasted %s", name, elapsed)
}
```

## Usage

```go
func BigIntFactorial(x big.Int) *big.Int {
    // Arguments to a defer statement is immediately evaluated and stored.
    // The deferred function receives the pre-evaluated values when its invoked.
    defer profile.Duration(time.Now(), "IntFactorial")

    y := big.NewInt(1)
    for one := big.NewInt(1); x.Sign() > 0; x.Sub(x, one) {
        y.Mul(y, x)
    }

    return x.Set(y)
}
```


================================================
FILE: stability/circuit-breaker.md
================================================
# Circuit Breaker Pattern

Similar to electrical fuses that prevent fires when a circuit that is connected
to the electrical grid starts drawing a high amount of power which causes the
wires to heat up and combust, the circuit breaker design pattern is a fail-first
mechanism that shuts down the circuit, request/response relationship or a
service in the case of software development, to prevent bigger failures.

**Note:** The words "circuit" and "service" are used synonymously throught this
document.

## Implementation

Below is the implementation of a very simple circuit breaker to illustrate the purpose
of the circuit breaker design pattern.

### Operation Counter

`circuit.Counter` is a simple counter that records success and failure states of
a circuit along with a timestamp and calculates the consecutive number of
failures.

```go
package circuit

import (
	"time"
)

type State int

const (
	UnknownState State = iota
	FailureState
	SuccessState
)

type Counter interface {
	Count(State)
	ConsecutiveFailures() uint32
	LastActivity() time.Time
	Reset()
}
```

### Circuit Breaker

Circuit is wrapped using the `circuit.Breaker` closure that keeps an internal operation counter.
It returns a fast error if the circuit has failed consecutively more than the specified threshold.
After a while it retries the request and records it.

**Note:** Context type is used here to carry deadlines, cancelation signals, and
other request-scoped values across API boundaries and between processes.

```go
package circuit

import (
	"context"
	"time"
)

type Circuit func(context.Context) error

func Breaker(c Circuit, failureThreshold uint32) Circuit {
	cnt := NewCounter()

	return func(ctx context) error {
		if cnt.ConsecutiveFailures() >= failureThreshold {
			canRetry := func(cnt Counter) {
				backoffLevel := Cnt.ConsecutiveFailures() - failureThreshold

				// Calculates when should the circuit breaker resume propagating requests
				// to the service
				shouldRetryAt := cnt.LastActivity().Add(time.Seconds * 2 << backoffLevel)

				return time.Now().After(shouldRetryAt)
			}

			if !canRetry(cnt) {
				// Fails fast instead of propagating requests to the circuit since
				// not enough time has passed since the last failure to retry
				return ErrServiceUnavailable
			}
		}

		// Unless the failure threshold is exceeded the wrapped service mimics the
		// old behavior and the difference in behavior is seen after consecutive failures
		if err := c(ctx); err != nil {
			cnt.Count(FailureState)
			return err
		}

		cnt.Count(SuccessState)
		return nil
	}
}
```

## Related Works

- [sony/gobreaker](https://github.com/sony/gobreaker) is a well-tested and intuitive circuit breaker implementation for real-world use cases.


================================================
FILE: structural/decorator.md
================================================
# Decorator Pattern
Decorator structural pattern allows extending the function of an existing object dynamically without altering its internals.

Decorators provide a flexible method to extend functionality of objects.

## Implementation
`LogDecorate` decorates a function with the signature `func(int) int` that 
manipulates integers and adds input/output logging capabilities.

```go
type Object func(int) int

func LogDecorate(fn Object) Object {
	return func(n int) int {
		log.Println("Starting the execution with the integer", n)

		result := fn(n)

		log.Println("Execution is completed with the result", result)

        return result
	}
}
```

## Usage
```go
func Double(n int) int {
    return n * 2
}

f := LogDecorate(Double)

f(5)
// Starting execution with the integer 5
// Execution is completed with the result 10
```

## Rules of Thumb
- Unlike Adapter pattern, the object to be decorated is obtained by **injection**.
- Decorators should not alter the interface of an object.


================================================
FILE: structural/proxy/main.go
================================================
package main

import (
	"fmt"
)

// For example:
// we must a execute some command
// so before that we must to create new terminal session
// and provide our user name and command
func main() {
	// Create new instance of Proxy terminal
	t, err := NewTerminal("gopher")
	if err != nil {
		// panic: User cant be empty
		// Or
		// panic: You (badUser) are not allowed to use terminal and execute commands
		panic(err.Error())
	}

	// Execute user command
	excResp, excErr := t.Execute("say_hi") // Proxy prints to STDOUT -> PROXY: Intercepted execution of user (gopher), asked command (say_hi)
	if excErr != nil {
		fmt.Printf("ERROR: %s\n", excErr.Error()) // Prints: ERROR: I know only how to execute commands: say_hi, man
	}

	// Show execution response
	fmt.Println(excResp) // Prints: gopher@go_term$: Hi gopher
}

/*
	From that it's can be different terminals realizations with different methods, propertys, yda yda...
*/

// ITerminal is interface, it's a public method whose implemented in Terminal(Proxy) and Gopher Terminal
type ITerminal interface {
	Execute(cmd string) (resp string, err error)
}

// GopherTerminal for example:
// Its a "huge" structure with different public methods
type GopherTerminal struct {
	// user is a current authorized user
	User string
}

// Execute just runs known commands for current authorized user
func (gt *GopherTerminal) Execute(cmd string) (resp string, err error) {
	// Set "terminal" prefix for output
	prefix := fmt.Sprintf("%s@go_term$:", gt.User)

	// Execute some asked commands if we know them
	switch cmd {
	case "say_hi":
		resp = fmt.Sprintf("%s Hi %s", prefix, gt.User)
	case "man":
		resp = fmt.Sprintf("%s Visit 'https://golang.org/doc/' for Golang documentation", prefix)
	default:
		err = fmt.Errorf("%s Unknown command", prefix)
	}

	return
}

/*
	And now we will create owr proxy to deliver user and commands to specific objects
*/

// Terminal is a implementation of Proxy, it's  validates and sends data to GopherTerminal
// As example before send commands, user must be authorized
type Terminal struct {
	currentUser    string
	gopherTerminal *GopherTerminal
}

// NewTerminal creates new instance of terminal
func NewTerminal(user string) (t *Terminal, err error) {
	// Check user if given correctly
	if user == "" {
		err = fmt.Errorf("User cant be empty")
		return
	}

	// Before we execute user commands, we validate current user, if he have rights to do it
	if authErr := authorizeUser(user); authErr != nil {
		err = fmt.Errorf("You (%s) are not allowed to use terminal and execute commands", user)
		return
	}

	// Create new instance of terminal and set valid user
	t = &Terminal{currentUser: user}

	return
}

// Execute intercepts execution of command, implements authorizing user, validates it and
// poxing command to real terminal (gopherTerminal) method
func (t *Terminal) Execute(command string) (resp string, err error) {
	// If user allowed to execute send commands then, for example we can decide which terminal can be used, remote or local etc..
	// but for example we just creating new instance of terminal,
	// set current user and send user command to execution in terminal
	t.gopherTerminal = &GopherTerminal{User: t.currentUser}

	// For example our proxy can log or output intercepted execution... etc
	fmt.Printf("PROXY: Intercepted execution of user (%s), asked command (%s)\n", t.currentUser, command)

	// Transfer data to original object and execute command
	if resp, err = t.gopherTerminal.Execute(command); err != nil {
		err = fmt.Errorf("I know only how to execute commands: say_hi, man")
		return
	}

	return
}

// authorize validates user right to execute commands
func authorizeUser(user string) (err error) {
	// As we use terminal like proxy, then
	// we will intercept user name to validate if it's allowed to execute commands
	if user != "gopher" {
		// Do some logs, notifications etc...
		err = fmt.Errorf("User %s in black list", user)
		return
	}

	return
}


================================================
FILE: structural/proxy.md
================================================
# Proxy Pattern

The [proxy pattern](https://en.wikipedia.org/wiki/Proxy_pattern) provides an object that controls access to another object, intercepting all calls.

## Implementation

The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate.

Short idea of implementation:
```go
    // To use proxy and to object they must implement same methods
    type IObject interface {
        ObjDo(action string)
    }

    // Object represents real objects which proxy will delegate data
    type Object struct {
        action string
    }

    // ObjDo implements IObject interface and handel's all logic
    func (obj *Object) ObjDo(action string) {
        // Action behavior
        fmt.Printf("I can, %s", action)
    }

    // ProxyObject represents proxy object with intercepts actions
    type ProxyObject struct {
        object *Object
    }

    // ObjDo are implemented IObject and intercept action before send in real Object
    func (p *ProxyObject) ObjDo(action string) {
        if p.object == nil {
            p.object = new(Object)
        }
        if action == "Run" {
            p.object.ObjDo(action) // Prints: I can, Run
        }
    }
```

## Usage
More complex usage of proxy as example: User creates "Terminal" authorizes and PROXY send execution command to real Terminal object
See [proxy/main.go](proxy/main.go) or [view in the Playground](https://play.golang.org/p/mnjKCMaOVE).


================================================
FILE: synchronization/semaphore.md
================================================
# Semaphore Pattern
A semaphore is a synchronization pattern/primitive that imposes mutual exclusion on a limited number of resources. 

## Implementation

```go
package semaphore

var (
	ErrNoTickets      = errors.New("semaphore: could not aquire semaphore")
	ErrIllegalRelease = errors.New("semaphore: can't release the semaphore without acquiring it first")
)

// Interface contains the behavior of a semaphore that can be acquired and/or released.
type Interface interface {
	Acquire() error
	Release() error
}

type implementation struct {
	sem     chan struct{}
	timeout time.Duration
}

func (s *implementation) Acquire() error {
	select {
	case s.sem <- struct{}{}:
		return nil
	case <-time.After(s.timeout):
		return ErrNoTickets
	}
}

func (s *implementation) Release() error {
	select {
	case _ = <-s.sem:
		return nil
	case <-time.After(s.timeout):
		return ErrIllegalRelease
	}

	return nil
}

func New(tickets int, timeout time.Duration) Interface {
	return &implementation{
		sem:     make(chan struct{}, tickets),
		timeout: timeout,
	}
}
```

## Usage
### Semaphore with Timeouts

```go
tickets, timeout := 1, 3*time.Second
s := semaphore.New(tickets, timeout)

if err := s.Acquire(); err != nil {
    panic(err)
}

// Do important work

if err := s.Release(); err != nil {
    panic(err)
}
```
### Semaphore without Timeouts (Non-Blocking)

```go
tickets, timeout := 0, 0
s := semaphore.New(tickets, timeout)

if err := s.Acquire(); err != nil {
    if err != semaphore.ErrNoTickets {
        panic(err)
    }

    // No tickets left, can't work :(
    os.Exit(1)
}
```
Download .txt
gitextract_krcxlr3l/

├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SUMMARY.md
├── behavioral/
│   ├── observer/
│   │   └── main.go
│   ├── observer.md
│   └── strategy.md
├── book.json
├── concurrency/
│   ├── bounded_parallelism.go
│   ├── bounded_parallelism.md
│   ├── generator.md
│   ├── parallelism.go
│   └── parallelism.md
├── creational/
│   ├── builder.md
│   ├── factory.md
│   ├── object-pool.md
│   └── singleton.md
├── idiom/
│   └── functional-options.md
├── messaging/
│   ├── fan_in.md
│   ├── fan_out.md
│   └── publish_subscribe.md
├── profiling/
│   └── timing.md
├── stability/
│   └── circuit-breaker.md
├── structural/
│   ├── decorator.md
│   ├── proxy/
│   │   └── main.go
│   └── proxy.md
└── synchronization/
    └── semaphore.md
Download .txt
SYMBOL INDEX (27 symbols across 4 files)

FILE: behavioral/observer/main.go
  type Event (line 12) | type Event struct
  type Observer (line 20) | type Observer interface
  type Notifier (line 28) | type Notifier interface
  type eventObserver (line 43) | type eventObserver struct
    method OnNotify (line 54) | func (o *eventObserver) OnNotify(e Event) {
  type eventNotifier (line 47) | type eventNotifier struct
    method Register (line 58) | func (o *eventNotifier) Register(l Observer) {
    method Deregister (line 62) | func (o *eventNotifier) Deregister(l Observer) {
    method Notify (line 66) | func (p *eventNotifier) Notify(e Event) {
  function main (line 72) | func main() {

FILE: concurrency/bounded_parallelism.go
  function walkFiles (line 17) | func walkFiles(done <-chan struct{}, root string) (<-chan string, <-chan...
  type result (line 43) | type result struct
  function digester (line 51) | func digester(done <-chan struct{}, paths <-chan string, c chan<- result) {
  function MD5All (line 66) | func MD5All(root string) (map[string][md5.Size]byte, error) {
  function main (line 105) | func main() {

FILE: concurrency/parallelism.go
  type result (line 15) | type result struct
  function sumFiles (line 25) | func sumFiles(done <-chan struct{}, root string) (<-chan result, <-chan ...
  function MD5All (line 72) | func MD5All(root string) (map[string][md5.Size]byte, error) {
  function main (line 93) | func main() {

FILE: structural/proxy/main.go
  function main (line 11) | func main() {
  type ITerminal (line 36) | type ITerminal interface
  type GopherTerminal (line 42) | type GopherTerminal struct
    method Execute (line 48) | func (gt *GopherTerminal) Execute(cmd string) (resp string, err error) {
  type Terminal (line 71) | type Terminal struct
    method Execute (line 98) | func (t *Terminal) Execute(command string) (resp string, err error) {
  function NewTerminal (line 77) | func NewTerminal(user string) (t *Terminal, err error) {
  function authorizeUser (line 117) | func authorizeUser(user string) (err error) {
Condensed preview — 29 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (62K chars).
[
  {
    "path": ".gitignore",
    "chars": 465,
    "preview": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture spe"
  },
  {
    "path": ".travis.yml",
    "chars": 1231,
    "preview": "language: node_js\n\nenv:\n  global:\n    - GH_REPO=\"github.com/tmrts/go-patterns\"\n    - secure: SRAVBGLCkoVpCNC5J43qC6xcQvi"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1071,
    "preview": "# Contribution Guidelines\n\nPlease ensure your pull request adheres to the following guidelines:\n\n- Make an individual pu"
  },
  {
    "path": "LICENSE",
    "chars": 10173,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 7466,
    "preview": "<p align=\"center\">\n  <img src=\"/gopher.png\" height=\"400\">\n  <h1 align=\"center\">\n    Go Patterns\n    <br>\n    <a href=\"ht"
  },
  {
    "path": "SUMMARY.md",
    "chars": 2890,
    "preview": "# Summary\n\n* [Go Patterns](/README.md)\n  * [Creational Patterns](/README.md#creational-patterns)\n    * [Abstract Factory"
  },
  {
    "path": "behavioral/observer/main.go",
    "chars": 2339,
    "preview": "// Package main serves as an example application that makes use of the observer pattern.\n// Playground: https://play.gol"
  },
  {
    "path": "behavioral/observer.md",
    "chars": 1722,
    "preview": "# Observer Pattern\n\nThe [observer pattern](https://en.wikipedia.org/wiki/Observer_pattern) allows a type instance to \"pu"
  },
  {
    "path": "behavioral/strategy.md",
    "chars": 1111,
    "preview": "# Strategy Pattern\nStrategy behavioral design pattern enables an algorithm's behavior to be selected at runtime.\n\nIt def"
  },
  {
    "path": "book.json",
    "chars": 351,
    "preview": "{\n    \"plugins\": [\n        \"-search\", \n        \"-lunr\",\n        \"github\",\n        \"edit-link\"\n    ],\n    \"pluginsConfig\""
  },
  {
    "path": "concurrency/bounded_parallelism.go",
    "chars": 3052,
    "preview": "package bounded_parallelism\n\nimport (\n\t\"crypto/md5\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"sync\""
  },
  {
    "path": "concurrency/bounded_parallelism.md",
    "chars": 326,
    "preview": "# Bounded Parallelism Pattern\n\n[Bounded parallelism](https://blog.golang.org/pipelines#TOC_9.) is similar to [parallelis"
  },
  {
    "path": "concurrency/generator.md",
    "chars": 848,
    "preview": "# Generator Pattern\n\n[Generators](https://en.wikipedia.org/wiki/Generator_(computer_programming)) yields a sequence of v"
  },
  {
    "path": "concurrency/parallelism.go",
    "chars": 2829,
    "preview": "package parallelism\n\nimport (\n\t\"crypto/md5\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"sync\"\n)\n\n// A"
  },
  {
    "path": "concurrency/parallelism.md",
    "chars": 278,
    "preview": "# Parallelism Pattern\n\n[Parallelism](https://blog.golang.org/pipelines#TOC_8.) allows multiple \"jobs\" or tasks to be run"
  },
  {
    "path": "creational/builder.md",
    "chars": 1169,
    "preview": "# Builder Pattern\n\nBuilder pattern separates the construction of a complex object from its\nrepresentation so that the sa"
  },
  {
    "path": "creational/factory.md",
    "chars": 1045,
    "preview": "# Factory Method Pattern\n\nFactory method creational design pattern allows creating objects without having\nto specify the"
  },
  {
    "path": "creational/object-pool.md",
    "chars": 921,
    "preview": "# Object Pool Pattern\n\nThe object pool creational design pattern is used to prepare and keep multiple\ninstances accordin"
  },
  {
    "path": "creational/singleton.md",
    "chars": 590,
    "preview": "# Singleton Pattern\n\nSingleton creational design pattern restricts the instantiation of a type to a single object.\n\n## I"
  },
  {
    "path": "idiom/functional-options.md",
    "chars": 1550,
    "preview": "# Functional Options\n\nFunctional options are a method of implementing clean/eloquent APIs in Go.\nOptions implemented as "
  },
  {
    "path": "messaging/fan_in.md",
    "chars": 1100,
    "preview": "Fan-In Messaging Patterns\n===================================\nFan-In is a messaging pattern used to create a funnel for "
  },
  {
    "path": "messaging/fan_out.md",
    "chars": 1179,
    "preview": "Fan-Out Messaging Pattern\n=========================\nFan-Out is a messaging pattern used for distributing work amongst wo"
  },
  {
    "path": "messaging/publish_subscribe.md",
    "chars": 1855,
    "preview": "Publish & Subscribe Messaging Pattern\n============\nPublish-Subscribe is a messaging pattern used to communicate messages"
  },
  {
    "path": "profiling/timing.md",
    "chars": 888,
    "preview": "# Timing Functions\n\nWhen optimizing code, sometimes a quick and dirty time measurement is required\nas opposed to utilizi"
  },
  {
    "path": "stability/circuit-breaker.md",
    "chars": 2747,
    "preview": "# Circuit Breaker Pattern\n\nSimilar to electrical fuses that prevent fires when a circuit that is connected\nto the electr"
  },
  {
    "path": "structural/decorator.md",
    "chars": 994,
    "preview": "# Decorator Pattern\nDecorator structural pattern allows extending the function of an existing object dynamically without"
  },
  {
    "path": "structural/proxy/main.go",
    "chars": 3973,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\n// For example:\n// we must a execute some command\n// so before that we must to create n"
  },
  {
    "path": "structural/proxy.md",
    "chars": 1511,
    "preview": "# Proxy Pattern\n\nThe [proxy pattern](https://en.wikipedia.org/wiki/Proxy_pattern) provides an object that controls acces"
  },
  {
    "path": "synchronization/semaphore.md",
    "chars": 1589,
    "preview": "# Semaphore Pattern\nA semaphore is a synchronization pattern/primitive that imposes mutual exclusion on a limited number"
  }
]

About this extraction

This page contains the full source code of the tmrts/go-patterns GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 29 files (55.9 KB), approximately 14.8k tokens, and a symbol index with 27 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!