mirror of
https://github.com/crazybber/go-pattern-examples.git
synced 2024-11-25 05:06:03 +03:00
finish flyweight pattern
This commit is contained in:
parent
12d826336d
commit
82d8c7cf02
75
.vscode/settings.json
vendored
75
.vscode/settings.json
vendored
@ -1,36 +1,41 @@
|
||||
{
|
||||
"editor.tabSize": 2,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.insertFinalNewline": true,
|
||||
"extensions.ignoreRecommendations": true,
|
||||
"workbench.colorCustomizations": {
|
||||
"activityBar.background": "#759570",
|
||||
"activityBar.activeBorder": "#cfd3ef",
|
||||
"activityBar.foreground": "#e7e7e7",
|
||||
"activityBar.hoverBackground": "#352cea",
|
||||
"activityBar.inactiveForeground": "#e7e7e799",
|
||||
"activityBarBadge.background": "#cfd3ef",
|
||||
"activityBarBadge.foreground": "#15202b",
|
||||
"titleBar.activeBackground": "#5e7959",
|
||||
"titleBar.inactiveBackground": "#5e795999",
|
||||
"titleBar.activeForeground": "#e7e7e7",
|
||||
"titleBar.inactiveForeground": "#e7e7e799",
|
||||
"statusBarItem.hoverBackground": "#352cea",
|
||||
"statusBar.foreground": "#e7e7e7",
|
||||
"panel.border": "#759570",
|
||||
"sideBar.border": "#759570",
|
||||
"editorGroup.border": "#759570"
|
||||
},
|
||||
"go.languageServerFlags": [],
|
||||
"go.lintOnSave": "file",
|
||||
"go.vetOnSave": "package",
|
||||
"go.useCodeSnippetsOnFunctionSuggest": true,
|
||||
"go.testFlags": ["-v"],
|
||||
"go.testTimeout": "10s",
|
||||
"go.formatTool": "goimports",
|
||||
"cSpell.allowCompoundWords": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
},
|
||||
}
|
||||
//https://vscode.readthedocs.io/en/latest/getstarted/settings/
|
||||
"editor.tabSize": 2,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.insertFinalNewline": true,
|
||||
"extensions.ignoreRecommendations": true,
|
||||
"workbench.colorCustomizations": {
|
||||
"activityBar.background": "#759570",
|
||||
"activityBar.activeBorder": "#cfd3ef",
|
||||
"activityBar.foreground": "#e7e7e7",
|
||||
"activityBar.hoverBackground": "#352cea",
|
||||
"activityBar.inactiveForeground": "#e7e7e799",
|
||||
"activityBarBadge.background": "#cfd3ef",
|
||||
"activityBarBadge.foreground": "#15202b",
|
||||
"titleBar.activeBackground": "#5e7959",
|
||||
"titleBar.inactiveBackground": "#5e795999",
|
||||
"titleBar.activeForeground": "#e7e7e7",
|
||||
"titleBar.inactiveForeground": "#e7e7e799",
|
||||
"statusBarItem.hoverBackground": "#352cea",
|
||||
"statusBar.foreground": "#e7e7e7",
|
||||
"panel.border": "#759570",
|
||||
"sideBar.border": "#759570",
|
||||
"editorGroup.border": "#759570"
|
||||
},
|
||||
"go.languageServerFlags": [],
|
||||
"go.lintOnSave": "file",
|
||||
"go.vetOnSave": "package",
|
||||
"go.useCodeSnippetsOnFunctionSuggest": true,
|
||||
"go.testFlags": [
|
||||
"-v"
|
||||
],
|
||||
"go.testTimeout": "10s",
|
||||
"go.formatTool": "goimports",
|
||||
"cSpell.allowCompoundWords": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
},
|
||||
"fileheader.Author":"Edward",
|
||||
"fileheader.tpl": "/* \r\n * @Description: https://github.com/crazybber \r\n * @Author: {author} \r\n * @Date: {createTime} \r\n * @Last Modified by: {lastModifiedBy} \r\n * @Last Modified time: {updateTime} \r\n */\r\n",
|
||||
"fileheader.LastModifiedBy": "Edward"
|
||||
}
|
||||
//https://vscode.readthedocs.io/en/latest/getstarted/settings/
|
||||
|
@ -1,4 +1,19 @@
|
||||
# 享元模式
|
||||
|
||||
享元模式从对象中剥离出不发生改变且多个实例需要的重复数据,独立出一个享元,使多个对象共享,从而节省内存以及减少对象数量。
|
||||
享元模式是细粒度控制主体构成的一种方式,英文叫 flyweight,单词分开看反倒更容易理解,fly-weight,看起来是要消减对象的大小/重量(size/weight),对!就是这个意思!抽取对象中的不变部分,使其能够容易的被复用或者共用,进而能够减小内存占用,优化性能,提高运行时效率,比如,会减少对象在内存分配/克隆时的空间大小,减小对象内存占用损耗,缩短响应时间等。
|
||||
|
||||
注意:实际上完整的享元模式,包含两部分可以被共享的部分,不可以被共享部分,两者组合起来才构成一个完整的整体,设计享元模式,严谨的讲需要针对可共享部分与不可共享两部分设计接口。
|
||||
|
||||
|
||||
单纯享元模式:在单纯享元模式中,所有的具体享元类都是可以共享的,不存在非共享具体享元类。
|
||||
复合享元模式:将一些单纯享元对象使用组合模式加以组合,还可以形成复合享元对象,这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者则可以共享。
|
||||
|
||||
享元的的可共享部分在程序是设计,一般是集中管理的,一般设计为一个存储map的,享元的不可共享部分,一般是即用即创建,完全的专有模式.
|
||||
|
||||
现实生活中的快递送货任务就一个很好的享元模式,快递公司的快递员是共享的,并且可以重复使用,快递公司不可能送一个快递雇一个快递员,否则,这个代价太大巨大了,但是快递员送的包裹是不一样,这是每个人的私有物品,所以不变的快递员+一直在变化的快递,才能构成一次完整的送货任务。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,59 +1,73 @@
|
||||
package flyweight
|
||||
|
||||
import "fmt"
|
||||
/*
|
||||
* @Description: github.com/crazybber
|
||||
* @Author: Edward
|
||||
* @Date: 2020-05-01 18:10:57
|
||||
* @Last Modified by: Edward
|
||||
* @Last Modified time: 2020-05-01 19:38:21
|
||||
*/
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ImageFlyweightFactory struct {
|
||||
maps map[string]*ImageFlyweight
|
||||
//IDeliverCompany 公司的能力
|
||||
type IDeliverCompany interface {
|
||||
//雇人
|
||||
Hire(name string)
|
||||
//送货任务
|
||||
DeliverTask(name string, packets []string)
|
||||
|
||||
GetDeliver(name string) IDeliver
|
||||
}
|
||||
|
||||
var imageFactory *ImageFlyweightFactory
|
||||
//DeliverCompany 快递公司
|
||||
type DeliverCompany struct {
|
||||
Employees map[string]IDeliver
|
||||
}
|
||||
|
||||
func GetImageFlyweightFactory() *ImageFlyweightFactory {
|
||||
if imageFactory == nil {
|
||||
imageFactory = &ImageFlyweightFactory{
|
||||
maps: make(map[string]*ImageFlyweight),
|
||||
}
|
||||
//IDeliver 快递员能做的事情
|
||||
type IDeliver interface {
|
||||
//送货
|
||||
DeliverPackets(packets []string)
|
||||
}
|
||||
|
||||
//Deliver 快递员工,员工是一个享元对象
|
||||
type Deliver struct {
|
||||
Name string //快递员的名字
|
||||
Packets []string //快递员的携带的快递,这一部分是变化的
|
||||
}
|
||||
|
||||
//Hire 雇佣新员工,员工是全公司共享
|
||||
func (d *DeliverCompany) Hire(name string) {
|
||||
if d.Employees == nil || len(d.Employees) == 0 {
|
||||
d.Employees = make(map[string]IDeliver)
|
||||
}
|
||||
return imageFactory
|
||||
}
|
||||
|
||||
func (f *ImageFlyweightFactory) Get(filename string) *ImageFlyweight {
|
||||
image := f.maps[filename]
|
||||
if image == nil {
|
||||
image = NewImageFlyweight(filename)
|
||||
f.maps[filename] = image
|
||||
if _, ok := d.Employees[name]; ok {
|
||||
fmt.Println("already hired")
|
||||
return
|
||||
}
|
||||
d.Employees[name] = &Deliver{Name: name}
|
||||
|
||||
return image
|
||||
fmt.Println("hired")
|
||||
}
|
||||
|
||||
type ImageFlyweight struct {
|
||||
data string
|
||||
//GetDeliver return Deliver
|
||||
func (d *DeliverCompany) GetDeliver(name string) IDeliver {
|
||||
|
||||
return d.Employees[name]
|
||||
|
||||
}
|
||||
|
||||
func NewImageFlyweight(filename string) *ImageFlyweight {
|
||||
// Load image file
|
||||
data := fmt.Sprintf("image data %s", filename)
|
||||
return &ImageFlyweight{
|
||||
data: data,
|
||||
}
|
||||
//DeliverTask 派员工送货
|
||||
func (d *DeliverCompany) DeliverTask(name string, packets []string) {
|
||||
|
||||
d.Employees[name].DeliverPackets(packets)
|
||||
|
||||
}
|
||||
|
||||
func (i *ImageFlyweight) Data() string {
|
||||
return i.data
|
||||
}
|
||||
//DeliverPackets 送货了
|
||||
func (d *Deliver) DeliverPackets(packets []string) {
|
||||
|
||||
type ImageViewer struct {
|
||||
*ImageFlyweight
|
||||
}
|
||||
|
||||
func NewImageViewer(filename string) *ImageViewer {
|
||||
image := GetImageFlyweightFactory().Get(filename)
|
||||
return &ImageViewer{
|
||||
ImageFlyweight: image,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *ImageViewer) Display() {
|
||||
fmt.Printf("Display: %s\n", i.Data())
|
||||
fmt.Println(d.Name, ": Delivered:", packets)
|
||||
}
|
||||
|
@ -1,19 +1,54 @@
|
||||
/*
|
||||
* @Description: github.com/crazybber
|
||||
* @Author: Edward
|
||||
* @Date: 2020-05-01 17:24:28
|
||||
* @Last Modified by: Edward
|
||||
* @Last Modified time: 2020-05-01 19:45:32
|
||||
*/
|
||||
package flyweight
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeliveryPackets(t *testing.T) {
|
||||
|
||||
dc := &DeliverCompany{Employees: make(map[string]IDeliver)}
|
||||
|
||||
dc.Hire("bob")
|
||||
dc.Hire("lily")
|
||||
dc.Hire("bob")
|
||||
|
||||
deliver1 := dc.GetDeliver("lily")
|
||||
|
||||
deliver2 := dc.GetDeliver("lily")
|
||||
|
||||
dc.DeliverTask("lily", []string{"box1", "box2"})
|
||||
|
||||
dc.DeliverTask("lily", []string{"box6", "box7", "box8"})
|
||||
|
||||
deliver2.DeliverPackets([]string{"box9", "box10", "box11"})
|
||||
|
||||
deliver1.DeliverPackets([]string{"box12"})
|
||||
|
||||
func ExampleFlyweight() {
|
||||
viewer := NewImageViewer("image1.png")
|
||||
viewer.Display()
|
||||
// Output:
|
||||
// Display: image data image1.png
|
||||
}
|
||||
|
||||
func TestFlyweight(t *testing.T) {
|
||||
viewer1 := NewImageViewer("image1.png")
|
||||
viewer2 := NewImageViewer("image1.png")
|
||||
func TestDeliverEmployee(t *testing.T) {
|
||||
dc := &DeliverCompany{Employees: make(map[string]IDeliver)}
|
||||
|
||||
if viewer1.ImageFlyweight != viewer2.ImageFlyweight {
|
||||
t.Fail()
|
||||
dc.Hire("bob")
|
||||
dc.Hire("lily")
|
||||
|
||||
deliver1 := dc.GetDeliver("lily")
|
||||
|
||||
deliver2 := dc.GetDeliver("lily")
|
||||
|
||||
dp1 := fmt.Sprintf("%p", deliver1)
|
||||
|
||||
dp2 := fmt.Sprintf("%p", deliver2)
|
||||
|
||||
if dp1 != dp2 {
|
||||
t.Error(dp1, "not the same with", dp2)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user