C++ 带装饰图案的线程安全

C++ 带装饰图案的线程安全,c++,multithreading,oop,design-patterns,C++,Multithreading,Oop,Design Patterns,这是相当长的,但我会尽量清楚 我有一个接口,我们把它叫做IFoo 类IFoo { 公众: 虚拟无效重置(常量条*条)=0; 虚拟整数计算(整数i)常数=0; }; 基本实现 class-FooBasic:public-IFoo { 私人: int_值; 公众: FooBasic(int-value):_-value(value){} 虚拟无效重置(常量条*条)重写{} 虚拟整数计算(inti)常量重写{return_value;} }; 我有一个基本的界面装饰 类FoodDecorator:

这是相当长的,但我会尽量清楚

我有一个接口,我们把它叫做
IFoo

类IFoo
{
公众:
虚拟无效重置(常量条*条)=0;
虚拟整数计算(整数i)常数=0;
};
基本实现

class-FooBasic:public-IFoo
{
私人:
int_值;
公众:
FooBasic(int-value):_-value(value){}
虚拟无效重置(常量条*条)重写{}
虚拟整数计算(inti)常量重写{return_value;}
};
我有一个基本的界面装饰

类FoodDecorator:公共IFoo
{
受保护的:
IFoo*(ufoo);
公众:
食物装饰师(IFoo*foo):\u foo(foo){}
虚拟无效重置(常量条*条)重写{{u foo->reset(条);}
虚拟整数计算(inti)常量重写{return\u foo->calculate(i);}
};
我有很多装饰器的实现,它们的形式几乎相同

class FooInt:public fooddecorator
{
私人:
国际;
int_z;
公众:
FooInt(IFoo*foo):FooDecorator(foo),y(0),z(0){}
虚拟无效重置(常量条*Bar)覆盖
{
_foo->reset(条);
_y=杆->费用功能(15);
_z=杆->费用功能(10);
}
虚拟整数计算(inti)常量重写{return\u y*\u foo->calculate(i)+\u z;}
};
FooIntStar类:公共FoodDecorator
{
私人:
常数int*z;
公众:
FooIntStar(IFoo*foo):FooDecorator(foo),z(nullptr){}
虚拟无效重置(常量条*Bar)覆盖
{
_foo->reset(条);
_z=条->费用开始函数();
}
虚拟整数计算(inti)常量重写{return\u foo->calculate(i)*\u z[i];}
};
这里的想法是,
IFoo
接口的客户机将首先调用
reset()
方法,传入他们的
Bar
对象。然后,他们将使用不同的整数参数调用
calculate()
方法数百万次。
IFoo
实现将在调用
reset()
时从
Bar
对象中提取一些信息,并使用它设置一些内部成员,然后使用这些成员装饰底层
IFoo
对象的结果。它们从bar对象中提取的内容取决于实现,可以是不同的类型/值

只要有一个客户端使用
IFoo
实现,这一切都可以正常工作。我现在尝试介绍一些线程,其中我有不同的客户端同时使用
IFoo
实现。每个客户端都有自己的
Bar
对象,但我希望它们使用与
IFoo
对象相同的实例(如果可能)。在当前状态下,这将不起作用,因为对
reset()
的调用设置了成员变量,即
reset()
方法不是
const

我的计划是创建一个workspace对象,然后传递给其他人。每个客户端都将拥有自己的工作区实例,以避免多个客户端使用同一对象时发生冲突。调用reset时,
IFoo
实现将在工作区中设置临时数据,而不使用内部成员。但是,由于不同实现所需的数据类型不同,因此提前设计此工作区很困难

我提出的一个想法是将这个工作区抽象化,并让实现对其进行扩展。所以我想把界面改成

//完全未定义的对象
结构IFooWorkspace
{
虚拟~IFooWorkspace(){}
};
类IFoo
{
公众:
虚拟IFooWorkspace*createWorkspace()常量=0;
虚拟无效重置(IFooWorkspace*工作区,常数条*Bar)常数=0;
虚拟整数计算(IFooWorkspace*workspace,inti)常数=0;
};
例如
FooInt
实现

class FooInt:public fooddecorator
{
私人:
//结构定义而不是成员变量
结构工作区:IFooWorkspace
{
WorkSpace():y(0),z(0),ws(nullptr){}
虚拟~WorkSpace(){delete}
国际;
int_z;
iFoooWorkspace*\uWS;
};
公众:
FooInt(IFoo*foo):FooDecorator(foo){}
虚拟IFooWorkspace*createWorkspace()常量重写
{
工作空间*ws=新工作空间;
ws->\u ws=\u foo->createWorkspace();
返回ws;
}
虚拟无效重置(IFooWorkspace*工作区,常量条*Bar)常量覆盖
{
工作空间&ws=dynamic_cast(*工作空间);
ws._y=bar->expensiventfunction(15);
ws._z=bar->expensiveIntFunction(10);
_foo->reset(ws.\u ws,bar);
}
虚拟整数计算(IFooWorkspace*工作空间,整数i)常数覆盖
{
const WorkSpace&ws=动态转换(*工作空间);
返回ws.\u y*\u foo->计算(ws.\u ws,i)+ws.\u z;
}
};
因此,新的计划是客户端首先调用
createWorkspace()
,并拥有返回的
IFooWorkspace
对象。然后对
reset()
calculate()
的后续调用应通过此工作区


我的问题是,这一切看起来相当复杂,我不确定
动态\u cast
的安全性和性能。所以问题是:这里有没有更简单、更干净的方法来实现线程安全?理想情况下,我希望避免为IFoo对象创建新实例。

如果需要规划的不同数据类型相对来说是可替换的(例如,
int
vs
double
),那么您可以尝试模板化
IFoo

实际上,只有在子类之间存在大量共享状态的情况下,引入
IFooWorkspace
才有意义,即如果
IFooWorkspace
的实际实现中包含某些内容。否则为什么要麻烦呢?你们之间没有实现脱钩
class IFooFactory
{
public:
    virtual IFoo create(const Bar* bar) = 0;
};

class IFoo
{
public:
    virtual int calculate(int i) const = 0;
};
class FooIntFactory : public IFooFactory
{
public:
    virtual IFoo create(const Bar* bar) const override
    {
        return new FooInt(bar);
    }
};