享元模式—Flyweight
1.模式定义:
享元模式(Flyweight ):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。
2.模式结构
- flyweight:抽象享元
- 具体享元角色:
- concrete_flyweight1:具体享元角色1
- concrete_flyweight2:具体享元角色2
- flyweight_factory:享元工厂
3.代码分析
- 3.1 main.cpp
#include"flyweight_factory.hpp"
#include<iostream>
using namespace std;
int main(int argc, char const *argv[])
{
flyweight_factory ff;
auto val1 = ff.get_flyweight("1");
val1->operate();
auto val2 = ff.get_flyweight("1");
val2->operate();
auto val3 = ff.get_flyweight("11");
val3->operate();
auto val4 = ff.get_flyweight("11");
val4->operate();
return 0;
}
- 3.2 抽象享元: flyweight.hpp
#ifndef FLYWEIGHT_HPP
# define FLYWEIGHT_HPP
#include<string>
using namespace std;
// 抽象享元
class flyweight
{
private:
string m_intrinsic; // 内部状态:可以共享的相同内容
protected:
string m_Extrinsic; // 外部状态:不能共享的内容
public:
flyweight(string Extrinsic){
m_Extrinsic = Extrinsic;
}
~flyweight(){}
string get_intrinsic() {
return m_intrinsic;
}
void set_intrinsic(string intrinsic) {
m_intrinsic = intrinsic;
}
virtual void operate(){}
};
#endif // FLYWEIGHT_HPP
- 3.3 具体享元角色: concrete_flyweight.hpp
#ifndef CONCRETE_FLYWEIGHT_HPP
# define CONCRETE_FLYWEIGHT_HPP
#include"flyweight.hpp"
#include<string>
#include<iostream>
using namespace std;
// 具体享元角色
// 具体享元角色1
class concrete_flyweight1: public flyweight
{
public:
concrete_flyweight1(string Extrinsic):flyweight(Extrinsic){}
~concrete_flyweight1(){
}
void operate() {
cout << "concrete_flyweight1::operate" << endl;
}
};
// 具体享元角色2
class concrete_flyweight2: public flyweight
{
public:
concrete_flyweight2(string Extrinsic):flyweight(Extrinsic){}
~concrete_flyweight2(){}
void operate() {
cout << "concrete_flyweight2::operate" << endl;
}
};
#endif // CONCRETE_FLYWEIGHT_HPP
- 3.4 享元工厂: flyweight_factory.hpp
#ifndef FLYWEIGHT_FACTORY_HPP
# define FLYWEIGHT_FACTORY_HPP
#include<map>
#include<string>
#include"flyweight.hpp"
#include"concrete_flyweight.hpp"
using namespace std;
// 享元工厂
class flyweight_factory
{
private:
static map<string, flyweight*> pool;
public:
flyweight_factory(){}
~flyweight_factory(){
for (auto it = pool.begin(); it != pool.end(); ++it) {
delete it->second;
it->second = nullptr;
}
}
static flyweight* get_flyweight(string Extrinsic) {
auto it = pool.find(Extrinsic);
if (it != pool.end()) {
return it->second;
} else if ((Extrinsic.size()%2) == 0) {
flyweight* fw2 = new concrete_flyweight2(Extrinsic);
pool[Extrinsic] = fw2;
return fw2;
}
flyweight* fw1 = new concrete_flyweight1(Extrinsic);
pool[Extrinsic] = fw1;
return fw1;
}
};
// 初始化池
map<string, flyweight*> flyweight_factory:: pool = map<string, flyweight*>();
#endif // FLYWEIGHT_FACTORY_HPP
- 3.5 实验结果:
concrete_flyweight1::operate
concrete_flyweight1::operate
concrete_flyweight2::operate
concrete_flyweight2::operate
4.优缺点
-
4.1 优点
- 4.1.1 相似对象内存共享,减少内存占用率,大大减少对象的创建和销毁,提高服务性能。
-
4.2 缺点
- 4.2.1 提高了系统复杂性,需要将对象分离出外部状态[不能共享的内容]和内部状态[可共享的内容]。
5.模式分析
-
5.1 享元模式目的是通过对象池化共享技术,解决系统对相似对象的频繁重复创建和销毁,对系统性能的影响,主要是减少内存占用空间;
-
5.2 享元模式主要使用了对象池、工厂方法设计模式、分离共享对象的内部和外部状态[通过外部状态查找共享对象],实现对象的多次复用。
6.实例:考试报名(go代码实现)
-
类图:
-
6.0: main.go
package main
import (
"fmt"
"./Flyweight"
)
func test_flyweight() {
sign_pool := flyweight.NewSignFactory()
for i := 0; i < 5; i++ {
subject := "subject" + strconv.FormatInt(int64(i), 10)
for j := 0; j < 30; j++ {
address := "address" + strconv.FormatInt(int64(j), 10)
key := subject + address
val, isNew := sign_pool.GetSignInfo(key)
// 一大败笔
if !isNew {
val.SetId((i + 1) * j)
val.SetSubject(subject)
val.SetPostAddress(address)
}
}
}
sign_info, isNew := sign_pool.GetSignInfo("subject1address1")
fmt.Println("sign info:", *sign_info, " <====> new", isNew)
}
func main() {
test_Flyweight()
}
- 6.1:共享报名信息:SignInfo.go
package flyweight
// 共享报名信息
type SignInfo struct {
id int
location string
subject string
postAddress string
}
func NewSignInfo() *SignInfo {
return &SignInfo{}
}
func (si *SignInfo) SetId(id int) {
si.id = id
}
func (si *SignInfo) GetId() (id int) {
return si.id
}
func (si *SignInfo) SetLocation(location string) {
si.location = location
}
func (si *SignInfo) GetLocation() (location string) {
return si.location
}
func (si *SignInfo) SetSubject(subject string) {
si.subject = subject
}
func (si *SignInfo) GetSubject() (subject string) {
return si.subject
}
func (si *SignInfo) SetPostAddress(postAddress string) {
si.postAddress = postAddress
}
func (si *SignInfo) GetPostAddress() (postAddress string) {
return si.postAddress
}
- 6.2: 报名工厂:SignFactory.go
package flyweight
// 报名工厂
type SignFactory struct {
Pool map[string]*SignInfo
}
func NewSignFactory() *SignFactory {
return &SignFactory{
Pool: make(map[string]*SignInfo),
}
}
func (sf *SignFactory) GetSignInfo(key string) (ret *SignInfo, new bool) {
val, ok := sf.Pool[key]
if ok {
ret = val
} else {
ret = NewSignInfo()
sf.Pool[key] = ret
}
return sf.Pool[key], ok
}
- 6.3 执行结果:
sign info: {2 subject1 address1} <====> new true