finish flyweight pattern

This commit is contained in:
Edward 2020-05-01 19:46:07 +08:00
parent 12d826336d
commit 82d8c7cf02
4 changed files with 158 additions and 89 deletions

View File

@ -25,12 +25,17 @@
"go.lintOnSave": "file",
"go.vetOnSave": "package",
"go.useCodeSnippetsOnFunctionSuggest": true,
"go.testFlags": ["-v"],
"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/

View File

@ -1,4 +1,19 @@
# 享元模式
享元模式从对象中剥离出不发生改变且多个实例需要的重复数据,独立出一个享元,使多个对象共享,从而节省内存以及减少对象数量。
享元模式是细粒度控制主体构成的一种方式,英文叫 flyweight单词分开看反倒更容易理解fly-weight,看起来是要消减对象的大小/重量(size/weight),对!就是这个意思!抽取对象中的不变部分,使其能够容易的被复用或者共用,进而能够减小内存占用,优化性能,提高运行时效率,比如,会减少对象在内存分配/克隆时的空间大小,减小对象内存占用损耗,缩短响应时间等。
注意:实际上完整的享元模式,包含两部分可以被共享的部分,不可以被共享部分,两者组合起来才构成一个完整的整体,设计享元模式,严谨的讲需要针对可共享部分与不可共享两部分设计接口。
单纯享元模式:在单纯享元模式中,所有的具体享元类都是可以共享的,不存在非共享具体享元类。
复合享元模式:将一些单纯享元对象使用组合模式加以组合,还可以形成复合享元对象,这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者则可以共享。
享元的的可共享部分在程序是设计一般是集中管理的一般设计为一个存储map的享元的不可共享部分一般是即用即创建完全的专有模式.
现实生活中的快递送货任务就一个很好的享元模式,快递公司的快递员是共享的,并且可以重复使用,快递公司不可能送一个快递雇一个快递员,否则,这个代价太大巨大了,但是快递员送的包裹是不一样,这是每个人的私有物品,所以不变的快递员+一直在变化的快递,才能构成一次完整的送货任务。

View File

@ -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
func GetImageFlyweightFactory() *ImageFlyweightFactory {
if imageFactory == nil {
imageFactory = &ImageFlyweightFactory{
maps: make(map[string]*ImageFlyweight),
}
}
return imageFactory
//DeliverCompany 快递公司
type DeliverCompany struct {
Employees map[string]IDeliver
}
func (f *ImageFlyweightFactory) Get(filename string) *ImageFlyweight {
image := f.maps[filename]
if image == nil {
image = NewImageFlyweight(filename)
f.maps[filename] = image
//IDeliver 快递员能做的事情
type IDeliver interface {
//送货
DeliverPackets(packets []string)
}
return image
//Deliver 快递员工,员工是一个享元对象
type Deliver struct {
Name string //快递员的名字
Packets []string //快递员的携带的快递,这一部分是变化的
}
type ImageFlyweight struct {
data string
//Hire 雇佣新员工,员工是全公司共享
func (d *DeliverCompany) Hire(name string) {
if d.Employees == nil || len(d.Employees) == 0 {
d.Employees = make(map[string]IDeliver)
}
if _, ok := d.Employees[name]; ok {
fmt.Println("already hired")
return
}
d.Employees[name] = &Deliver{Name: name}
fmt.Println("hired")
}
func NewImageFlyweight(filename string) *ImageFlyweight {
// Load image file
data := fmt.Sprintf("image data %s", filename)
return &ImageFlyweight{
data: data,
}
//GetDeliver return Deliver
func (d *DeliverCompany) GetDeliver(name string) IDeliver {
return d.Employees[name]
}
func (i *ImageFlyweight) Data() string {
return i.data
//DeliverTask 派员工送货
func (d *DeliverCompany) DeliverTask(name string, packets []string) {
d.Employees[name].DeliverPackets(packets)
}
type ImageViewer struct {
*ImageFlyweight
}
//DeliverPackets 送货了
func (d *Deliver) DeliverPackets(packets []string) {
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)
}

View File

@ -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)
}
}