- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有以下问题。考虑方案:
在绘图类中我有:
Box* b1 = new Box();
Box* b2 = new Box();
Box* b3 = new Box();
Box* b4 = new Box();
b1->setArea(20);
b2->setArea(30);
b3->setArea( b1->getArea() * 7/3 + b2->getArea() / 5 );
b4->setArea( b3->getArea() + b1->getArea() );
我想要系统的以下行为:
我想知道我应该如何使用 C++ 正确实现此功能?
我看了观察者模式,但似乎不适用于这种情况,这是正确的吗?
谢谢
最佳答案
似乎如果“盒子”正在观察系统中的单个“事件”,例如以“b1”作为参数的“BOX_AREA_CHANGED”,它们都可以根据需要更改自己的区域。
所以这确实感觉像是一种“观察者”模式。问题在于让所有参与者(盒子)在创建/销毁时根据需要附加/分离。此外,您还希望他们详细注册特定事件,以便您可以轻松地针对他们的操作。如果所有框都响应“BOX_AREA_CHANGED”,但只有少数框响应“BOX_MOVED”,您不希望前者在后一条消息发生变化时做出响应。
我把类似这样的东西放在一起,叫做通知程序。这是它的基本要点:
界面最终是这样的:
/*
The Notifier is a singleton implementation of the Subject/Observer design
pattern. Any class/instance which wishes to participate as an observer
of an event can derive from the Notified base class and register itself
with the Notifier for enumerated events.
Notifier derived classes MUST implement the notify function, which has
a prototype of:
void Notify(const NOTIFIED_EVENT_TYPE_T& event, void* data)
This is a data object passed from the Notifier class. The structure
passed has a void* in it. There is no illusion of type safety here
and it is the responsibility of the user to ensure it is cast properly.
In most cases, it will be "NULL".
Classes derived from Notified do not need to deregister (though it may
be a good idea to do so) as the base class destructor will attempt to
remove itself from the Notifier system automatically.
The event type is an enumeration and not a string as it is in many
"generic" notification systems. In practical use, this is for a closed
application where the messages will be known at compile time. This allows
us to increase the speed of the delivery by NOT having a
dictionary keyed lookup mechanism. Some loss of generality is implied
by this.
This class/system is NOT thread safe, but could be made so with some
mutex wrappers. It is safe to call Attach/Detach as a consequence
of calling Notify(...).
*/
class Notified;
class Notifier : public SingletonDynamic<Notifier>
{
public:
typedef enum
{
NE_MIN = 0,
NE_DEBUG_BUTTON_PRESSED = NE_MIN,
NE_DEBUG_LINE_DRAW_ADD_LINE_PIXELS,
NE_DEBUG_TOGGLE_VISIBILITY,
NE_DEBUG_MESSAGE,
NE_RESET_DRAW_CYCLE,
NE_VIEWPORT_CHANGED,
NE_MAX,
} NOTIFIED_EVENT_TYPE_T;
private:
typedef vector<NOTIFIED_EVENT_TYPE_T> NOTIFIED_EVENT_TYPE_VECTOR_T;
typedef map<Notified*,NOTIFIED_EVENT_TYPE_VECTOR_T> NOTIFIED_MAP_T;
typedef map<Notified*,NOTIFIED_EVENT_TYPE_VECTOR_T>::iterator NOTIFIED_MAP_ITER_T;
typedef vector<Notified*> NOTIFIED_VECTOR_T;
typedef vector<NOTIFIED_VECTOR_T> NOTIFIED_VECTOR_VECTOR_T;
NOTIFIED_MAP_T _notifiedMap;
NOTIFIED_VECTOR_VECTOR_T _notifiedVector;
NOTIFIED_MAP_ITER_T _mapIter;
// This vector keeps a temporary list of observers that have completely
// detached since the current "Notify(...)" operation began. This is
// to handle the problem where a Notified instance has called Detach(...)
// because of a Notify(...) call. The removed instance could be a dead
// pointer, so don't try to talk to it.
vector<Notified*> _detached;
int32 _notifyDepth;
void RemoveEvent(NOTIFIED_EVENT_TYPE_VECTOR_T& orgEventTypes, NOTIFIED_EVENT_TYPE_T eventType);
void RemoveNotified(NOTIFIED_VECTOR_T& orgNotified, Notified* observer);
public:
virtual void Reset();
virtual bool Init() { Reset(); return true; }
virtual void Shutdown() { Reset(); }
void Attach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType);
// Detach for a specific event
void Detach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType);
// Detach for ALL events
void Detach(Notified* observer);
/* The design of this interface is very specific. I could
* create a class to hold all the event data and then the
* method would just have take that object. But then I would
* have to search for every place in the code that created an
* object to be used and make sure it updated the passed in
* object when a member is added to it. This way, a break
* occurs at compile time that must be addressed.
*/
void Notify(NOTIFIED_EVENT_TYPE_T, const void* eventData = NULL);
/* Used for CPPUnit. Could create a Mock...maybe...but this seems
* like it will get the job done with minimal fuss. For now.
*/
// Return all events that this object is registered for.
vector<NOTIFIED_EVENT_TYPE_T> GetEvents(Notified* observer);
// Return all objects registered for this event.
vector<Notified*> GetNotified(NOTIFIED_EVENT_TYPE_T event);
};
/* This is the base class for anything that can receive notifications.
*/
class Notified
{
public:
virtual void Notify(Notifier::NOTIFIED_EVENT_TYPE_T eventType, const void* eventData) = 0;
virtual ~Notified();
};
typedef Notifier::NOTIFIED_EVENT_TYPE_T NOTIFIED_EVENT_TYPE_T;
注意:Notified 类只有一个函数,此处为 Notify(...)。因为 void* 不是类型安全的,所以我创建了其他版本,其中 notify 看起来像:
virtual void Notify(Notifier::NOTIFIED_EVENT_TYPE_T eventType, int value);
virtual void Notify(Notifier::NOTIFIED_EVENT_TYPE_T eventType, const string& str);
相应的 Notify(...) 方法已添加到通知程序本身。所有这些都使用一个函数来获取“目标列表”,然后在目标上调用适当的函数。这很好用,并且让接收者不必做丑陋的转换。
这似乎运作良好。解决方法贴在网上here连同源代码。这是一个相对较新的设计,因此非常感谢任何反馈。
关于c++ - 符号属性观察c++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18984729/
你能比较一下属性吗 我想禁用文本框“txtName”。有两种方式 使用javascript,txtName.disabled = true 使用 ASP.NET, 哪种方法更好,为什么? 最佳答案 我
Count 属性 返回一个集合或 Dictionary 对象包含的项目数。只读。 object.Count object 可以是“应用于”列表中列出的任何集合或对
CompareMode 属性 设置并返回在 Dictionary 对象中比较字符串关键字的比较模式。 object.CompareMode[ = compare] 参数
Column 属性 只读属性,返回 TextStream 文件中当前字符位置的列号。 object.Column object 通常是 TextStream 对象的名称。
AvailableSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。 object.AvailableSpace object 应为 Drive 
Attributes 属性 设置或返回文件或文件夹的属性。可读写或只读(与属性有关)。 object.Attributes [= newattributes] 参数 object
AtEndOfStream 属性 如果文件指针位于 TextStream 文件末,则返回 True;否则如果不为只读则返回 False。 object.A
AtEndOfLine 属性 TextStream 文件中,如果文件指针指向行末标记,就返回 True;否则如果不是只读则返回 False。 object.AtEn
RootFolder 属性 返回一个 Folder 对象,表示指定驱动器的根文件夹。只读。 object.RootFolder object 应为 Dr
Path 属性 返回指定文件、文件夹或驱动器的路径。 object.Path object 应为 File、Folder 或 Drive 对象的名称。 说明 对于驱动器,路径不包含根目录。
ParentFolder 属性 返回指定文件或文件夹的父文件夹。只读。 object.ParentFolder object 应为 File 或 Folder 对象的名称。 说明 以下代码
Name 属性 设置或返回指定的文件或文件夹的名称。可读写。 object.Name [= newname] 参数 object 必选项。应为 File 或&
Line 属性 只读属性,返回 TextStream 文件中的当前行号。 object.Line object 通常是 TextStream 对象的名称。 说明 文件刚
Key 属性 在 Dictionary 对象中设置 key。 object.Key(key) = newkey 参数 object 必选项。通常是 Dictionary 
Item 属性 设置或返回 Dictionary 对象中指定的 key 对应的 item,或返回集合中基于指定的 key 的&
IsRootFolder 属性 如果指定的文件夹是根文件夹,返回 True;否则返回 False。 object.IsRootFolder object 应为&n
IsReady 属性 如果指定的驱动器就绪,返回 True;否则返回 False。 object.IsReady object 应为 Drive&nbs
FreeSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。只读。 object.FreeSpace object 应为 Drive 对象的名称。
FileSystem 属性 返回指定的驱动器使用的文件系统的类型。 object.FileSystem object 应为 Drive 对象的名称。 说明 可
Files 属性 返回由指定文件夹中所有 File 对象(包括隐藏文件和系统文件)组成的 Files 集合。 object.Files object&n
我是一名优秀的程序员,十分优秀!