update
This commit is contained in:
parent
23aea2d07a
commit
7d8fbfcd30
8
.idea/golang-design-patterns.iml
generated
Normal file
8
.idea/golang-design-patterns.iml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
6
.idea/misc.xml
generated
Normal file
6
.idea/misc.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
</project>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/golang-design-patterns.iml" filepath="$PROJECT_DIR$/.idea/golang-design-patterns.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
279
.idea/workspace.xml
generated
Normal file
279
.idea/workspace.xml
generated
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="1a1353c4-bdd9-41be-9088-eda7b22a7be5" name="Default" comment="" />
|
||||||
|
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||||
|
<option name="TRACKING_ENABLED" value="true" />
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="FileEditorManager">
|
||||||
|
<leaf>
|
||||||
|
<file leaf-file-name="README.md" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/README.md">
|
||||||
|
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
|
||||||
|
<state split_layout="SPLIT">
|
||||||
|
<first_editor relative-caret-position="135">
|
||||||
|
<caret line="9" lean-forward="true" selection-start-line="9" selection-end-line="9" />
|
||||||
|
</first_editor>
|
||||||
|
<second_editor />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="README.md" pinned="false" current-in-tab="true">
|
||||||
|
<entry file="file://$PROJECT_DIR$/singleton/README.md">
|
||||||
|
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
|
||||||
|
<state split_layout="SPLIT">
|
||||||
|
<first_editor relative-caret-position="426">
|
||||||
|
<caret line="194" column="59" selection-start-line="194" selection-start-column="59" selection-end-line="194" selection-end-column="59" />
|
||||||
|
</first_editor>
|
||||||
|
<second_editor />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="lazy-loading.go" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/singleton/lazy-loading.go">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="348">
|
||||||
|
<caret line="27" selection-start-line="27" selection-end-line="34" selection-end-column="1" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="starving-loading.go" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/singleton/starving-loading.go">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="68">
|
||||||
|
<caret line="9" selection-start-line="9" selection-end-line="31" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="double-check-lock.go" pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/singleton/double-check-lock.go">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="120">
|
||||||
|
<caret line="11" selection-start-line="11" selection-end-line="33" selection-end-column="1" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#14#39#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
</leaf>
|
||||||
|
</component>
|
||||||
|
<component name="FileTemplateManagerImpl">
|
||||||
|
<option name="RECENT_TEMPLATES">
|
||||||
|
<list>
|
||||||
|
<option value="Go File" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="GOROOT" path="/usr/local/Cellar/go/1.10.3/libexec" />
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="IdeDocumentHistory">
|
||||||
|
<option name="CHANGED_PATHS">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/README.md" />
|
||||||
|
<option value="$PROJECT_DIR$/singleton/main.go" />
|
||||||
|
<option value="$PROJECT_DIR$/singleton/starving-loading.go" />
|
||||||
|
<option value="$PROJECT_DIR$/singleton/lazy-loading.go" />
|
||||||
|
<option value="$PROJECT_DIR$/singleton/double-check-lock.go" />
|
||||||
|
<option value="$PROJECT_DIR$/singleton/README.md" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||||
|
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||||
|
<component name="JsGulpfileManager">
|
||||||
|
<detection-done>true</detection-done>
|
||||||
|
<sorting>DEFINITION_ORDER</sorting>
|
||||||
|
</component>
|
||||||
|
<component name="NodePackageJsonFileManager">
|
||||||
|
<packageJsonPaths />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectFrameBounds" fullScreen="true">
|
||||||
|
<option name="width" value="1440" />
|
||||||
|
<option name="height" value="900" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectView">
|
||||||
|
<navigator proportions="" version="1">
|
||||||
|
<foldersAlwaysOnTop value="true" />
|
||||||
|
</navigator>
|
||||||
|
<panes>
|
||||||
|
<pane id="Scope" />
|
||||||
|
<pane id="ProjectPane">
|
||||||
|
<subPane>
|
||||||
|
<expand>
|
||||||
|
<path>
|
||||||
|
<item name="golang-design-patterns" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="golang-design-patterns" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<item name="golang-design-patterns" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="golang-design-patterns" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="singleton" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
</expand>
|
||||||
|
<select />
|
||||||
|
</subPane>
|
||||||
|
</pane>
|
||||||
|
</panes>
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent">
|
||||||
|
<property name="DefaultGoTemplateProperty" value="Go File" />
|
||||||
|
<property name="go.gopath.indexing.explicitly.defined" value="true" />
|
||||||
|
<property name="go.sdk.automatically.set" value="true" />
|
||||||
|
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||||
|
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
||||||
|
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="RunDashboard">
|
||||||
|
<option name="ruleStates">
|
||||||
|
<list>
|
||||||
|
<RuleState>
|
||||||
|
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||||
|
</RuleState>
|
||||||
|
<RuleState>
|
||||||
|
<option name="name" value="StatusDashboardGroupingRule" />
|
||||||
|
</RuleState>
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="RunManager" selected="Go Build.go build double-check-lock.go">
|
||||||
|
<configuration name="go build double-check-lock.go" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
|
||||||
|
<module name="golang-design-patterns" />
|
||||||
|
<working_directory value="$PROJECT_DIR$/" />
|
||||||
|
<go_parameters value="-i" />
|
||||||
|
<kind value="FILE" />
|
||||||
|
<filePath value="$PROJECT_DIR$/singleton/double-check-lock.go" />
|
||||||
|
<package value="github.com/silsuer/golang-design-patterns" />
|
||||||
|
<directory value="$PROJECT_DIR$/" />
|
||||||
|
</configuration>
|
||||||
|
<configuration name="go build lazy-loading.go" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
|
||||||
|
<module name="golang-design-patterns" />
|
||||||
|
<working_directory value="$PROJECT_DIR$/" />
|
||||||
|
<go_parameters value="-i" />
|
||||||
|
<kind value="FILE" />
|
||||||
|
<filePath value="$PROJECT_DIR$/singleton/lazy-loading.go" />
|
||||||
|
<package value="github.com/silsuer/golang-design-patterns" />
|
||||||
|
<directory value="$PROJECT_DIR$/" />
|
||||||
|
</configuration>
|
||||||
|
<configuration name="go build main.go" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
|
||||||
|
<module name="golang-design-patterns" />
|
||||||
|
<working_directory value="$PROJECT_DIR$/" />
|
||||||
|
<go_parameters value="-i" />
|
||||||
|
<kind value="FILE" />
|
||||||
|
<filePath value="$PROJECT_DIR$/singleton/main.go" />
|
||||||
|
<package value="github.com/silsuer/golang-design-patterns" />
|
||||||
|
<directory value="$PROJECT_DIR$/" />
|
||||||
|
</configuration>
|
||||||
|
<configuration name="go build starving-loading.go" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
|
||||||
|
<module name="golang-design-patterns" />
|
||||||
|
<working_directory value="$PROJECT_DIR$/" />
|
||||||
|
<go_parameters value="-i" />
|
||||||
|
<kind value="FILE" />
|
||||||
|
<filePath value="$PROJECT_DIR$/singleton/starving-loading.go" />
|
||||||
|
<package value="github.com/silsuer/golang-design-patterns" />
|
||||||
|
<directory value="$PROJECT_DIR$/" />
|
||||||
|
</configuration>
|
||||||
|
<list>
|
||||||
|
<item itemvalue="Go Build.go build main.go" />
|
||||||
|
<item itemvalue="Go Build.go build lazy-loading.go" />
|
||||||
|
<item itemvalue="Go Build.go build starving-loading.go" />
|
||||||
|
<item itemvalue="Go Build.go build double-check-lock.go" />
|
||||||
|
</list>
|
||||||
|
<recent_temporary>
|
||||||
|
<list>
|
||||||
|
<item itemvalue="Go Build.go build double-check-lock.go" />
|
||||||
|
<item itemvalue="Go Build.go build starving-loading.go" />
|
||||||
|
<item itemvalue="Go Build.go build lazy-loading.go" />
|
||||||
|
<item itemvalue="Go Build.go build main.go" />
|
||||||
|
</list>
|
||||||
|
</recent_temporary>
|
||||||
|
</component>
|
||||||
|
<component name="ToolWindowManager">
|
||||||
|
<frame x="0" y="0" width="1440" height="900" extended-state="0" />
|
||||||
|
<editor active="true" />
|
||||||
|
<layout>
|
||||||
|
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.25" />
|
||||||
|
<window_info anchor="bottom" id="TODO" order="6" />
|
||||||
|
<window_info anchor="bottom" id="Docker" show_stripe_button="false" />
|
||||||
|
<window_info anchor="bottom" id="Event Log" side_tool="true" />
|
||||||
|
<window_info anchor="right" id="Database" />
|
||||||
|
<window_info anchor="bottom" id="Database Changes" show_stripe_button="false" />
|
||||||
|
<window_info anchor="bottom" id="Run" order="2" visible="true" weight="0.32969698" />
|
||||||
|
<window_info anchor="bottom" id="Version Control" />
|
||||||
|
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
|
||||||
|
<window_info anchor="bottom" id="Terminal" weight="0.32969698" />
|
||||||
|
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
|
||||||
|
<window_info id="Favorites" side_tool="true" />
|
||||||
|
<window_info anchor="bottom" id="Find" order="1" />
|
||||||
|
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
|
||||||
|
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
||||||
|
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
||||||
|
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
||||||
|
<window_info anchor="bottom" id="Message" order="0" />
|
||||||
|
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
|
||||||
|
</layout>
|
||||||
|
</component>
|
||||||
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
<option name="version" value="1" />
|
||||||
|
</component>
|
||||||
|
<component name="VcsContentAnnotationSettings">
|
||||||
|
<option name="myLimit" value="2678400000" />
|
||||||
|
</component>
|
||||||
|
<component name="editorHistoryManager">
|
||||||
|
<entry file="file://$PROJECT_DIR$/README.md">
|
||||||
|
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
|
||||||
|
<state split_layout="SPLIT">
|
||||||
|
<first_editor relative-caret-position="135">
|
||||||
|
<caret line="9" lean-forward="true" selection-start-line="9" selection-end-line="9" />
|
||||||
|
</first_editor>
|
||||||
|
<second_editor />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/singleton/lazy-loading.go">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="348">
|
||||||
|
<caret line="27" selection-start-line="27" selection-end-line="34" selection-end-column="1" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/singleton/starving-loading.go">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="68">
|
||||||
|
<caret line="9" selection-start-line="9" selection-end-line="31" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/singleton/double-check-lock.go">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="120">
|
||||||
|
<caret line="11" selection-start-line="11" selection-end-line="33" selection-end-column="1" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#14#39#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/singleton/README.md">
|
||||||
|
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
|
||||||
|
<state split_layout="SPLIT">
|
||||||
|
<first_editor relative-caret-position="426">
|
||||||
|
<caret line="194" column="59" selection-start-line="194" selection-start-column="59" selection-end-line="194" selection-end-column="59" />
|
||||||
|
</first_editor>
|
||||||
|
<second_editor />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</component>
|
||||||
|
</project>
|
55
README.md
55
README.md
@ -1,2 +1,55 @@
|
|||||||
# golang-design-patterns
|
# golang-design-patterns
|
||||||
使用golang实现各种设计模式
|
|
||||||
|
## 使用golang实现各种设计模式
|
||||||
|
|
||||||
|
- 创建型模式
|
||||||
|
|
||||||
|
1. [单例模式]()
|
||||||
|
|
||||||
|
2. 工厂方法模式
|
||||||
|
|
||||||
|
3. 抽象工厂模式
|
||||||
|
|
||||||
|
4. 建造者模式
|
||||||
|
|
||||||
|
5. 原型模式
|
||||||
|
|
||||||
|
- 行为型模式
|
||||||
|
|
||||||
|
1. 访问者模式
|
||||||
|
|
||||||
|
2. 模板模式
|
||||||
|
|
||||||
|
3. 策略模式
|
||||||
|
|
||||||
|
4. 状态模式
|
||||||
|
|
||||||
|
5. 观察者模式
|
||||||
|
|
||||||
|
6. 备忘录模式
|
||||||
|
|
||||||
|
7. 中介者模式
|
||||||
|
|
||||||
|
8. 迭代器模式
|
||||||
|
|
||||||
|
9. 解释器模式
|
||||||
|
|
||||||
|
10. 命令模式
|
||||||
|
|
||||||
|
11. 责任链模式
|
||||||
|
|
||||||
|
- 结构型模式
|
||||||
|
|
||||||
|
1. 适配器模式
|
||||||
|
|
||||||
|
2. 桥接模式
|
||||||
|
|
||||||
|
3. 组合模式
|
||||||
|
|
||||||
|
4. 装饰模式
|
||||||
|
|
||||||
|
5. 外观模式
|
||||||
|
|
||||||
|
6. 亨元模式
|
||||||
|
|
||||||
|
7. 代理模式
|
196
singleton/README.md
Normal file
196
singleton/README.md
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
# 单例模式
|
||||||
|
|
||||||
|
> wiki百科: 单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。
|
||||||
|
|
||||||
|
|
||||||
|
单例模式要实现的效果就是,对于应用单例模式的类,整个程序中只存在一个实例化对象
|
||||||
|
|
||||||
|
go并不是一种面向对象的语言,所以我们使用结构体来替代
|
||||||
|
|
||||||
|
有几种方式:
|
||||||
|
|
||||||
|
- 懒汉模式
|
||||||
|
|
||||||
|
- 饿汉模式
|
||||||
|
|
||||||
|
- 双重检查锁机制
|
||||||
|
|
||||||
|
下面拆分讲解:
|
||||||
|
|
||||||
|
### 懒汉模式
|
||||||
|
|
||||||
|
1. 构建一个示例结构体
|
||||||
|
|
||||||
|
```go
|
||||||
|
type example struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
2. 设置一个私有变量作为每次要返回的单例
|
||||||
|
|
||||||
|
```go
|
||||||
|
var instance *example
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 写一个可以获取单例的方法
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetExample() *example {
|
||||||
|
|
||||||
|
// 存在线程安全问题,高并发时有可能创建多个对象
|
||||||
|
if instance == nil {
|
||||||
|
instance = new(example)
|
||||||
|
}
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. 测试一下
|
||||||
|
|
||||||
|
```go
|
||||||
|
func main() {
|
||||||
|
s := GetExample()
|
||||||
|
s.name = "第一次赋值单例模式"
|
||||||
|
fmt.Println(s.name)
|
||||||
|
|
||||||
|
s2 := GetExample()
|
||||||
|
fmt.Println(s2.name)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
懒汉模式存在线程安全问题,在第3步的时候,如果有多个线程同时调用了这个方法,
|
||||||
|
那么都会检测到`instance`为`nil`,就会创建多个对象,所以出现了饿汉模式...
|
||||||
|
|
||||||
|
|
||||||
|
### 饿汉模式
|
||||||
|
|
||||||
|
与懒汉模式类似,不再多说,直接上代码
|
||||||
|
|
||||||
|
```go
|
||||||
|
|
||||||
|
// 构建一个结构体,用来实例化单例
|
||||||
|
type example2 struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 声明一个私有变量,作为单例
|
||||||
|
var instance2 *example2
|
||||||
|
|
||||||
|
// init函数将在包初始化时执行,实例化单例
|
||||||
|
func init() {
|
||||||
|
instance2 = new(example2)
|
||||||
|
instance2.name = "初始化单例模式"
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetInstance2() *example2 {
|
||||||
|
return instance2
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := GetInstance2()
|
||||||
|
fmt.Println(s.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
饿汉模式将在包加载的时候就创建单例对象,当程序中用不到该对象时,浪费了一部分空间
|
||||||
|
|
||||||
|
和懒汉模式相比,更安全,但是会减慢程序启动速度
|
||||||
|
|
||||||
|
|
||||||
|
### 双重检查机制
|
||||||
|
|
||||||
|
懒汉模式存在线程安全问题,一般我们使用互斥锁来解决有可能出现的数据不一致问题
|
||||||
|
|
||||||
|
所以修改上面的`GetInstance()` 方法如下:
|
||||||
|
|
||||||
|
```go
|
||||||
|
var mux Sync.Mutex
|
||||||
|
func GetInstance() *example {
|
||||||
|
mux.Lock()
|
||||||
|
defer mux.Unlock()
|
||||||
|
if instance == nil {
|
||||||
|
instance = &example{}
|
||||||
|
}
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
如果这样去做,每一次请求单例的时候,都会加锁和减锁,而锁的用处只在于解决对象初始化的时候可能出现的并发问题
|
||||||
|
当对象被创建之后,加锁就失去了意义,会拖慢速度,所以我们就引入了双重检查机制(`Check-lock-Check`),
|
||||||
|
也叫`DCL`(`Double Check Lock`), 代码如下:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetInstance() *example {
|
||||||
|
if instance == nil { // 单例没被实例化,才会加锁
|
||||||
|
mux.Lock()
|
||||||
|
defer mux.Unlock()
|
||||||
|
if instance == nil { // 单例没被实例化才会创建
|
||||||
|
instance = &example{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这样只有当对象未初始化的时候,才会又加锁和减锁的操作
|
||||||
|
|
||||||
|
但是又出现了另一个问题:每一次访问都要检查两次,为了解决这个问题,我们可以使用golang标准包中的方法进行原子性操作:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "sync"
|
||||||
|
import "sync/atomic"
|
||||||
|
|
||||||
|
var initialized uint32
|
||||||
|
|
||||||
|
func GetInstance() *example {
|
||||||
|
|
||||||
|
// 一次判断即可返回
|
||||||
|
if atomic.LoadUInt32(&initialized) == 1 {
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
mux.Lock()
|
||||||
|
defer mux.Unlock()
|
||||||
|
if initialized == 0 {
|
||||||
|
instance = &example{}
|
||||||
|
atomic.StoreUint32(&initialized, 1) // 原子装载
|
||||||
|
}
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
```
|
||||||
|
以上代码只需要经过一次判断即可返回单例,但是golang标准包中其实给我们提供了相关的方法:
|
||||||
|
|
||||||
|
`sync.Once`的`Do`方法可以实现在程序运行过程中只运行一次其中的回调,所以最终简化的代码如下:
|
||||||
|
|
||||||
|
```go
|
||||||
|
|
||||||
|
type example3 struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
var instance3 *example3
|
||||||
|
var once sync.Once
|
||||||
|
|
||||||
|
func GetInstance3() *example3 {
|
||||||
|
|
||||||
|
once.Do(func() {
|
||||||
|
instance3 = new(example3)
|
||||||
|
instance3.name = "第一次赋值单例"
|
||||||
|
})
|
||||||
|
return instance3
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
e1 := GetInstance3()
|
||||||
|
fmt.Println(e1.name)
|
||||||
|
|
||||||
|
e2 := GetInstance3()
|
||||||
|
fmt.Println(e2.name)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
单例模式是开发中经常用到的设计模式,我在制作自己的web框架 [silsuer/bingo](https://github.com/silsuer/bingo) 的时候
|
||||||
|
在环境变量控制、配置项控制等位置都用到了这种模式。
|
||||||
|
|
||||||
|
想把所有设计模式使用golang实现一遍,开了个新坑[silsuer/golang-design-patterns](https://github.com/silsuer/golang-design-patterns),
|
||||||
|
这是第一篇,以后会陆续更新,需要请自取~
|
34
singleton/double-check-lock.go
Normal file
34
singleton/double-check-lock.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 双重锁检查机制
|
||||||
|
*/
|
||||||
|
|
||||||
|
type example3 struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
var instance3 *example3
|
||||||
|
var once sync.Once
|
||||||
|
|
||||||
|
func GetInstance3() *example3 {
|
||||||
|
|
||||||
|
once.Do(func() {
|
||||||
|
instance3 = new(example3)
|
||||||
|
instance3.name = "第一次赋值单例"
|
||||||
|
})
|
||||||
|
return instance3
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
e1 := GetInstance3()
|
||||||
|
fmt.Println(e1.name)
|
||||||
|
|
||||||
|
e2 := GetInstance3()
|
||||||
|
fmt.Println(e2.name)
|
||||||
|
}
|
35
singleton/lazy-loading.go
Normal file
35
singleton/lazy-loading.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 单例模式之懒汉模式
|
||||||
|
* 非线程安全
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 首先构造一个结构体
|
||||||
|
type example struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置一个变量作为单例变量,这是一个私有变量,包外不可访问
|
||||||
|
var instance *example
|
||||||
|
|
||||||
|
// 写一个方法用来返回单例
|
||||||
|
func GetExample() *example {
|
||||||
|
|
||||||
|
// 存在线程安全问题,高并发时有可能创建多个对象
|
||||||
|
if instance == nil {
|
||||||
|
instance = new(example)
|
||||||
|
}
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := GetExample()
|
||||||
|
s.name = "第一次赋值单例模式"
|
||||||
|
fmt.Println(s.name)
|
||||||
|
|
||||||
|
s2 := GetExample()
|
||||||
|
fmt.Println(s2.name)
|
||||||
|
}
|
31
singleton/starving-loading.go
Normal file
31
singleton/starving-loading.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 饿汉模式
|
||||||
|
* 在类加载时就初始化对象
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 构建一个结构体,用来实例化单例
|
||||||
|
type example2 struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 声明一个私有变量,作为单例
|
||||||
|
var instance2 *example2
|
||||||
|
|
||||||
|
// init函数将在包初始化时执行,实例化单例
|
||||||
|
func init() {
|
||||||
|
instance2 = new(example2)
|
||||||
|
instance2.name = "初始化单例模式"
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetInstance2() *example2 {
|
||||||
|
return instance2
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := GetInstance2()
|
||||||
|
fmt.Println(s.name)
|
||||||
|
}
|
Reference in New Issue
Block a user