简单工厂模式

This commit is contained in:
刘洪宝 2018-11-02 11:58:27 +08:00
parent e5b93af318
commit 40f7a0fd11
9 changed files with 180 additions and 311 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.idea

View File

@ -1,8 +0,0 @@
<?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
View File

@ -1,6 +0,0 @@
<?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
View File

@ -1,8 +0,0 @@
<?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
View File

@ -1,6 +0,0 @@
<?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
View File

@ -1,279 +0,0 @@
<?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>

View File

@ -2,17 +2,23 @@
## 使用golang实现各种设计模式 ## 使用golang实现各种设计模式
> golang的最佳实践中并不建议在应用中使用大量的设计模式望周知
> Keep It Simple, Stupid.
- 创建型模式 - 创建型模式
1. [单例模式](https://github.com/silsuer/golang-design-patterns/blob/master/singleton/README.md) 1. [单例模式](https://github.com/silsuer/golang-design-patterns/blob/master/singleton/README.md)
2. 工厂方法模式 2. 简单工厂模式
3. 抽象工厂模式 3. 工厂方法模式
4. 建造者模式 4. 抽象工厂模式
5. 原型模式 5. 建造者模式
6. 原型模式
- 行为型模式 - 行为型模式

View File

@ -0,0 +1,114 @@
# 简单工厂模式
> wiki: 简单工厂模式并不属于 GoF 23 个经典设计模式,但通常将它作为学习其他工厂模式的基础,它的设计思想很简单,其基本流程如下:
> 首先将需要创建的各种不同对象(例如各种不同的 Chart 对象)的相关代码封装到不同的类中,这些类称为具体产品类,而将它们公共的代码进行抽象和提取后封装在一个抽象产品类中,每一个具体产品类都是抽象产品类的子类;然后提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方法,该方法可以根据所传入的参数不同创建不同的具体产品对象;客户端只需调用工厂类的工厂方法并传入相应的参数即可得到一个产品对象。
> 简单工厂模式定义如下:
> 简单工厂模式Simple Factory Pattern定义一个工厂类它可以根据参数的不同返回不同类的实例被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态static方法因此简单工厂模式又被称为静态工厂方法Static Factory Method模式它属于类创建型模式。
> 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。简单工厂模式结构比较简单,其核心是工厂类的设计,其结构如图所示
![](http://wiki.jikexueyuan.com/project/design-pattern-creation/images/20130711143612921.jpg)
上面都是我抄来的...
大概要做的事情就是,当我们想要创建一个对象的时候,调用同一个方法,传入不同的参数就可以返回给我们不同的对象了
当然,前提是这些对象对应的类都实现了相同的接口
**例如:**
我们创建一个工厂结构体,并且创建一个产品接口,工厂可以创建产品,只要在工厂的某个方法中传入不同的参数,就可以返回实现产品接口的不同的对象,
1. 创建工厂结构体:
```go
type Factory struct {
}
```
2. 创建产品接口,这里为了方便,只写了一个方法,请根据自己的需要扩展
```go
type Product interface {
create()
}
```
3. 创建两个产品产品1和产品2它们实现了产品接口:
```go
// 产品1实现产品接口
type Product1 struct {
}
func (p1 Product1) create() {
fmt.Println("this is product 1")
}
// 产品2实现产品接口
type Product2 struct {
}
func (p1 Product2) create() {
fmt.Println("this is product 2")
}
```
2. 为工厂结构体添加一个方法用于生产产品(实例化对象):
```go
func (f Factory) Generate(name string) Product {
switch name {
case "product1":
return Product1{}
case "product2":
return Product2{}
default:
return nil
}
}
```
3. 这样就可以通过传入不同的方法得到不同的产品实例了:
```go
// 创建一个工厂类,在应用中可以将这个工厂类实例作为一个全局变量
factory := new(Factory)
// 在工厂类中传入不同的参数,获取不同的实例
p1 := factory.Generate("product1")
p1.create() // output: this is product 1
p2 := factory.Generate("product2")
p2.create() // output: this is product 2
```
上面的例子只是为了解释工厂模式的思想而设置的最简单的例子,下面举一个在实际中应用的例子:
`bingo-log` 是一个`go`语言的日志包,可以自定义日志输出格式,这里就用到了简单工厂模式,所有实现了 `Connector` 接口的结构体都可以作为参数传入日志结构体中,达到自定义输出格式的目的
项目地址: [bingo-log](https://github.com/silsuer/bingo-log)
思路解析: [基于go开发日志处理包](https://juejin.im/post/5bcd796f51882577b82ffaee)
请直接去项目 `README.md` 中查看使用方法,去思路解析中查看整体的设计思路
下面说说工厂模式的优缺点:
- 优点: 工厂类是整个工厂模式的核心,我们只需要传入给定的信息,就可以创建所需实例,在多人协作的时候,无需知道对象之间的内部依赖,可以直接创建,有利于整个软件体系结构的优化
- 缺点: 工厂类中包含了所有实例的创建逻辑,一旦这个工厂类出现问题,所有实例都会受到影响,并且,工厂类中生产的产品都基于一个共同的接口,一旦要添加不同种类的产品,这就会增加工厂类的复杂度,将不同种类的产品混合在一起,违背了单一职责,系统的灵活性和可维护性都会降低,并且当新增产品的时候,必须要修改工厂类,违背了『系统对扩展开放,对修改关闭』的原则
所以我们还有更加复杂的设计模式去适应更加复杂的系统~
且听下回分解~ ~
**此文章的源码都在这个仓库中: [golang设计模式](https://github.com/silsuer/golang-design-patterns)**
> 打个广告,推荐一下自己写的 go web框架 [bingo](https://github.com/silsuer/bingo),求star求PR ~

View File

@ -0,0 +1,55 @@
package main
import "fmt"
// 简单工厂模式
// 产品接口,所有可以通过工厂实例创建的对象都会实现这个接口
type Product interface {
create()
}
// 工厂类
type Factory struct {
}
// 工厂创建产品的方法,传入一个产品名,返回这个产品的实例
func (f Factory) Generate(name string) Product {
switch name {
case "product1":
return Product1{}
case "product2":
return Product2{}
default:
return nil
}
}
// 产品1实现产品接口
type Product1 struct {
}
func (p1 Product1) create() {
fmt.Println("this is product 1")
}
// 产品2实现产品接口
type Product2 struct {
}
func (p1 Product2) create() {
fmt.Println("this is product 2")
}
func main() {
// 创建一个工厂类,在应用中可以将这个工厂类实例作为一个全局变量
factory := new(Factory)
// 在工厂类中传入不同的参数,获取不同的实例
p1 := factory.Generate("product1")
p1.create() // output: this is product 1
p2 := factory.Generate("product2")
p2.create() // output: this is product 2
}