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.
210 lines
4.1 KiB
C++
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;
|
|
};
|