You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kev/Drawer/Module/GeoSigmaDraw/ObjectProxyFactory.h

210 lines
4.1 KiB
C++

#pragma once
#include <functional>
#include <any>
#include "ActionAddItem.h"
#include "ItemEraser.h"
#include "DrawOperator/Util.h"
#include "Util.h"
/**
* 对象代理类,用于获取和设置对象属性
*/
class ObjectProxy
{
public:
virtual ~ObjectProxy() = default;
/**
* 获取属性,为了通用,我们全部使用字符串
*
* \param name 属性名称
* \return 属性值
*/
virtual CString GetProperty(const CString& name) const = 0;
/**
* 设置属性
*
* \param name 属性名称
* \param value 属性值
*/
virtual void SetProperty(const CString& name, const CString& value) = 0;
};
/**
* 橡皮擦代理对象
*/
class CItemEraserProxy : public ObjectProxy
{
public:
CItemEraserProxy(CItemEraser* eraser)
: m_eraser(eraser)
{
assert(m_eraser != nullptr);
}
CString GetProperty(const CString& name) const override
{
if (name == EraserMode)
{
return GetEraserMode();
}
else if (name == EraserRadius)
{
return GetEraserRadius();
}
else
{
return "";
}
}
void SetProperty(const CString& name, const CString& value) override
{
if (name == EraserMode)
{
SetEraserMode(value);
}
else if (name == EraserRadius)
{
SetEraserRadius(value);
}
}
private:
CString GetEraserMode() const
{
switch (m_eraser->GetEraserMode())
{
case EraserMode::Normal:
return Normal;
break;
case EraserMode::Segments:
return Segments;
break;
case EraserMode::Nodes:
return Nodes;
break;
default:
return "";
}
}
void SetEraserMode(const CString& mode)
{
if (mode == Normal)
{
m_eraser->SetEraserMode(EraserMode::Normal);
}
else if (mode == Segments)
{
m_eraser->SetEraserMode(EraserMode::Segments);
}
if (mode == Nodes)
{
m_eraser->SetEraserMode(EraserMode::Nodes);
}
}
CString GetEraserRadius() const
{
return ToCString(m_eraser->GetEraserRadius());
}
void SetEraserRadius(const CString& value)
{
int radius = _ttoi(value);
m_eraser->SetEraserRadius(radius);
}
CItemEraser* m_eraser;
const LPCTSTR EraserMode = _T("EraserMode");
const LPCTSTR EraserRadius = _T("EraserRadius");
const LPCTSTR Normal = _T("Normal");
const LPCTSTR Segments = _T("Segments");
const LPCTSTR Nodes =_T("Nodes");
};
/**
* @class ObjectProxyFactory
* @brief 代理对象工厂类,用于根据类型名称动态创建对应的代理对象。
*
* 此工厂类维护一个构造函数映射表,可以注册和注销特定类型的构造器。
* 客户端通过名称和构造参数创建相应的代理对象,支持运行时多态性和灵活的对象构建。
*/
class ObjectProxyFactory
{
public:
/**
* @brief 构造函数,初始化并注册默认的代理构造器。
*
* 使用 typeid 注册类型名称,避免手动拼写错误;
* 提供默认的 CItemEraser 类型代理构造器。
*/
ObjectProxyFactory()
{
// 我们在注册时使用 typeid 以免后缀名拼写错误,但是我们注册接口不这么做,对外提供灵活性
RegisterConstructor<CItemEraserProxy, CItemEraser*>(typeid(CItemEraser).name());
}
/**
* @brief 注册一个代理对象的构造函数。
*
* @tparam Proxy 要创建的代理类类型,需继承自 ObjectProxy。
* @tparam Arg 构造 Proxy 所需的参数类型。
* @param name 用于标识该构造函数的名称(一般为目标类型的名称)。
*/
template <typename Proxy, typename Arg>
void RegisterConstructor(const CString& name)
{
auto constructor = [](std::any arg) -> std::unique_ptr<ObjectProxy>
{
return std::make_unique<Proxy>(std::any_cast<Arg>(arg));
};
m_constructors[name] = constructor;
}
/**
* @brief 注销一个已注册的构造函数。
*
* @param name 要注销的构造器名称。
*/
void UnregisterConstructor(const CString& name)
{
auto it = m_constructors.find(name);
if (it != m_constructors.end())
{
m_constructors.erase(it);
}
}
/**
* @brief 根据名称和参数创建对应的代理对象。
*
* @param name 目标类型的名称(必须已注册构造器)。
* @param arg 构造该对象所需的参数(需与注册时一致)。
* @return std::unique_ptr<ObjectProxy> 成功则返回代理对象,失败返回 nullptr。
*/
std::unique_ptr<ObjectProxy> Create(const CString& name, std::any arg) const
{
auto it = m_constructors.find(name);
if (it != m_constructors.end())
{
return it->second(arg);
}
return nullptr;
}
private:
using constructor = std::function <std::unique_ptr<ObjectProxy>(std::any)>;
std::unordered_map<CString, constructor, CStringHash> m_constructors;
};