【声明】本题目来源于卡码网(题目页面 (kamacoder.com))
【提示:如果不想看文字介绍,可以直接跳转到C++编码部分】
【简介】什么是享元模式 -- 可重复使用
????????享元模式是?种结构型设计模式,在享元模式中,对象被设计为可共享的,可以被多个上下?使?,?不必在每个上下?中都创建新的对象。
????????想要了解享元模式,就必须要区分什么是内部状态,什么是外部状态。
????????举个例?,图书馆中有很多相同的书籍,但每本书都可以被多个?借阅,图书馆?的书就是内部状态,?就是外部状态。
????????再举个开发中的例?,假设我们在构建?个简单的图形编辑器,?户可以在画布上绘制不同类型的图形,?图形就是所有图形对象的内部状态(不变的),?图形的坐标位置就是图形对象的外部状态(变化的)。
????????如果图形编辑器中有成千上万的图形对象,每个图形对象都独?创建并存储其内部状态,那么系统的内存占?可能会很?,在这种情况下,享元模式共享相同类型的图形对象,每种类型的图形对象只需创建?个共享实例,然后通过设置不同的坐标位置个性化每个对象,通过共享相同的内部状态,降低了对象的创建和内存占?成本。
【基本结构】
????????享元模式包括以下?个重要??:
【简易实现】
?????????享元模式的实现通常涉及以下步骤:(以Java代码作以说明)
1.?定义享元接?,接受外部状态作为参数并进?处理。
// 步骤 1: 定义享元接?
interface Flyweight {
// 操作外部状态
void operation(String externalState);
}
2.?实现具体享元类, 存储内部状态。
// 步骤 2: 实现具体享元类
class ConcreteFlyweight implements Flyweight {
private String intrinsicState; // 内部状态
public ConcreteFlyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
@Override
public void operation(String externalState) {
System.out.println("Intrinsic State: " + intrinsicState + ", External State: "
+ externalState);
}
}
3.?创建享元??类,创建并管理Flyweight 对象,当?户请求?个Flyweight 时,享元??会提供?个已经创建的实例或者创建?个。
class FlyweightFactory {
private Map<String, Flyweight> flyweights = new HashMap<>();
public Flyweight getFlyweight(String key) {
if (!flyweights.containsKey(key)) {
flyweights.put(key, new ConcreteFlyweight(key));
}
return flyweights.get(key);
}
}
4.?客户端使?享元模式
public class Main {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
// 获取或创建享元对象,并传递外部状态
Flyweight flyweight1 = factory.getFlyweight("A");
flyweight1.operation("External State 1");
Flyweight flyweight2 = factory.getFlyweight("B");
flyweight2.operation("External State 2");
Flyweight flyweight3 = factory.getFlyweight("A"); // 【重复使?!】已存在的享元对象
flyweight3.operation("External State 3");
}
}
【使用场景】
????????使?享元模式的关键在于包含?量相似对象,并且这些对象的内部状态可以共享。具体的应?场景包括?本编辑器,图形编辑器,游戏中的??创建,这些对象的内部状态?较固定(外观,技能,形状),但是外部状态变化?较?时,可以使?。
【编码部分】
1. 题目描述
????????在一个图形编辑器中,用户可以绘制不同类型的图形,包括圆形(CIRCLE)、矩形(RECTANGLE)、三角形(TRIANGLE)等。现在,请你实现一个图形绘制程序,要求能够共享相同类型的图形对象,以减少内存占用;
2. 输入描述
???????输入包含多行,每行表示一个绘制命令。每个命令包括两部分:?图形类型(Circle、Rectangle 或 Triangle)?绘制的坐标位置(两个整数,分别表示 x 和 y);
3. 输出描述
????????对于每个绘制命令,输出相应图形被绘制的位置信息。如果图形是首次绘制,输出 "drawn at",否则输出 "shared at"。
4. C++ 编码部分
/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file FlyWeightMode.hpp
* @brief 享元模式
* @autor 写代码的小恐龙er
* @date 2024/01/13
*/
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
// 形状枚举类
enum class ShapeType{
CIRCLE, // 圆形
RECTANGLE,// 矩形
TRIANGLE, // 三角形
};
// 前置声明
// 图形位置
class Position;
// 1 -- 享元接口类
class Shape;
// 2 -- 具体实现享元接口
class ConcreteShape;
// 3 -- 享元工厂
class ShapeFactory;
// 图形位置
class Position
{
// 成员数据
private:
int _x;
int _y;
// 成员函数
public:
Position(){}
Position(int x, int y){
this->_x = x;
this->_y = y;
}
// 成员函数获取接口
int GetX(){
return _x;
}
int GetY(){
return _y;
}
};
// 1 -- 享元接口类
class Shape
{
// 接口函数
public:
virtual void DrawShape(Position *position) = 0;
};
// 2 -- 具体实现享元接口
class ConcreteShape : public Shape
{
// 成员数据
private:
// 形状类型
ShapeType _shapeType;
// 首次绘制标志
bool _firstTime = true;
// 成员函数
public:
// 通过 形状类型来创建具体的对象
ConcreteShape(ShapeType shapeType){
this->_shapeType = shapeType;
}
// 设置是否首次绘制标志位
void SetFirstTime(bool flag){
this->_firstTime = flag;
}
// 重载基类的接口函数
void DrawShape(Position *position){
string outStr = "";
switch(_shapeType)
{
case ShapeType::CIRCLE:
outStr = "CIRCLE";
break;
case ShapeType::RECTANGLE:
outStr = "RECTANGLE";
break;
case ShapeType::TRIANGLE:
outStr = "TRIANGLE";
break;
}
if(_firstTime) outStr += " drawn at (";
else outStr += " shared at (";
std::cout << outStr << (position->GetX()) << ", " << (position->GetY()) << ")" << endl;
}
};
// 3 -- 享元工厂
class ShapeFactory
{
// 成员数据
private:
// 包含可扩展的享元类
std::map<ShapeType, Shape*> _shapesMap;
// 成员函数
public:
Shape* GetShape(ShapeType type){
std::map<ShapeType, Shape*>::iterator pos = _shapesMap.find(type);
if(pos == _shapesMap.end())
{
// 如果在map中找不到具体的形状实现类 则新建
_shapesMap.insert(make_pair(type, new ConcreteShape(type)));
}
// 返回 具体的形状实现类
return _shapesMap[type];
}
};
int main()
{
// 形状类型
string type;
// x y
int x = 0;
int y = 0;
// 新建位置类
Position *position = nullptr;
// 新建享元工厂类
ShapeFactory *shapeFactory = new ShapeFactory();
while(std::cin >> type >> x >> y)
{
// 形状类型
ShapeType shapeType;
if(type == "CIRCLE")
{
shapeType = static_cast<ShapeType>(0);
}
else if(type == "RECTANGLE")
{
shapeType = static_cast<ShapeType>(1);
}
else if(type == "TRIANGLE")
{
shapeType = static_cast<ShapeType>(2);
}
// 位置类
position = new Position(x, y);
// 具体的享元实现类
Shape *shape = shapeFactory->GetShape(shapeType);
// 先进行绘制操作
shape->DrawShape(position);
// 通过 dynamic_cast 向下类型转换
ConcreteShape *concreteShape = dynamic_cast<ConcreteShape *> (shape);
if(concreteShape == nullptr) return 0;
// 再将该类型的标志位置为false
concreteShape->SetFirstTime(false);
}
// 析构
if(position != nullptr){
delete position;
position = nullptr;
}
delete shapeFactory;
shapeFactory = nullptr;
return 0;
}
......
To be continued.