- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在从事一个实现专有协议(protocol)的服务器项目。服务端是用C++工厂模式实现的,现在面临向下转型的问题。
我正在研究的协议(protocol)是为慢速网络自动控制而设计的,例如RS485、ZigBee、窄带PLC等。我们用工厂模式设计了主服务器。当接收到一个新的帧时,我们首先识别该帧的关联设备类型,调用工厂方法生成一个新的“解析器”实例,并将该帧分派(dispatch)给解析器实例。
我们的专有协议(protocol)是用纯二进制实现的,我们可能需要的所有信息都记录在框架本身中,因此可以尽可能简单地定义基本接口(interface)。我们还将为我们的工厂实现自动注册方法(此处省略与 std::map 操作相关的详细代码):
// This is our "interface" base-class
class parser
{
public:
virtual int parse(unsigned char *) = 0;
virtual ~parser() { }
};
// The next two classes are used for factory pattern
class instance_generator
{
public:
virtual parser *generate() = 0;
};
class parser_factory
{
private:
static std::map<int,instance_generator*> classDB;
public:
static void add(int id, instance_generator &genrator);
parser *get_instance(int id);
};
// the two template classes are implementations of "auto-regisrtation"
template <class G, int ID> class real_generator : public instance_generator
{
public:
real_generator() { parser_factory::add(ID,this); }
parser *generate() { return new G; }
};
template <class T, int N> class auto_reg : virtual public parser
{
private:
static real_generator<T,N> instance;
public:
auto_reg() { instance; }
};
template <class T, int N> parser_generator<T,N> auto_reg<T,N>::instance;
// And these are real parser implementations for each device type
class light_sensor : public auto_reg<light_sensor,1>
{
public:
int parse(unsigned char *str)
{
/* do something here */
}
};
class power_breaker : public auto_reg<power_breaker,2>
{
public:
int parse(unsigned char *str)
{
/* do something here */
}
};
/* other device parser */
这种工厂模式效果很好,很容易扩展新的设备类型。
但是,最近我们正在尝试与提供类似功能的现有控制系统进行交互。目标系统很旧,它只提供一个基于 ASCII 的、类似 AT 命令的串行接口(interface)。我们已经设法解决了与 PTY 的通信问题,但现在要解决的问题是解析器的实现。
目标系统的命令接口(interface)非常有限。我不能只是等待并监听传入的内容,我必须轮询状态,而且我必须轮询两次——第一次轮询 header ,第二次轮询有效负载——以获得完整的命令。这对我们的实现来说是个问题,因为我必须将两个帧传递给解析器实例,这样它才能工作:
class legacy_parser : virtual public parser
{
public:
legacy_parser() { }
int parse(unsigned char *str)
{
/* CAN NOT DO ANYTHING WITHOUT COMPLETE FRAMES */
}
virtual int parse(unsigned char *header, unsigned char *payload) = 0;
};
class legacy_IR_sensor :
public legacy_parser,
public auto_reg<legacy_IR_sensor,20>
{
public:
legacy_IR_sensor(){ }
int parse(unsigned char *header, unsigned char *payload)
{
/* Now we can finally parse the complete frame */
}
};
换句话说,我们需要调用派生类的一个方法,而该方法并没有在基类中定义。我们正在使用工厂模式来生成派生类的实例。
现在我们有几个选择:
简单地将两个字符串连接成一个是行不通的。两个字符串都包含一些设备指定的信息,需要分别解析。如果我们采用这种方法,我们将在连接字符串之前从解析器实例中执行一些“预解析”。我们认为这不是一个好主意。
将 parser_factory::get_instance() 的返回向下转换为 legacy_parser。
创建另一个独立工厂,它只包含从 legacy_parser 派生的类。
更改 instance_generator 和 parser_factory 的定义,使它们也可以生成 (legacy_parser*),同时保持所有现有代码不受影响:
class instance_generator
{
public:
virtual parser *generate() = 0;
virtual legacy_parser *generate_legacy() { return NULL; }
};
class extended_parser_factory : public parser_factory
{
public:
legacy_parser *get_legacy_instance(int id);
};
使用访问者模式实现“智能指针”以处理从 legacy_parser 派生的实例:
class smart_ptr
{
public:
virtual void set(parser *p) = 0;
virtual void set(legacy_parser *p) = 0;
};
class parser
{
public:
parser() { }
virtual int parse(unsigned char *) = 0;
virtual void copy_ptr(smart_ptr &sp) // implement "Visitor" pattern
{
sp.set(this);
}
virtual ~parser() { }
};
class legacy_parser : virtual public parser
{
public:
legacy_parser() { }
void copy_ptr(smart_ptr &sp) // implement "Visitor" pattern
{
sp.set(this);
}
int parse(unsigned char *str)
{
/* CAN NOT DO ANYTHING WITHOUT COMPLETE FRAMES */
}
virtual int parse(unsigned char *header, unsigned char *payload) = 0;
};
class legacy_ptr : public smart_ptr
{
private:
parser *miss;
legacy_parser *hit;
public:
legacy_ptr& operator=(parser *rhv)
{
rhv->copy_ptr(*this);
return *this;
}
void set(parser* ptr)
{
miss=ptr;
/* ERROR! Do some log or throw exception */
}
void set(legacy_parser *ptr)
{
hit = ptr;
}
legacy_parser& operator*()
{
return *hit;
}
~legacy_ptr()
{
if(miss) {
delete miss;
}
if(hit) {
delete hit;
}
}
};
很明显,使用 dynamic_cast<> 向下转型对我们来说是最简单的方法,但我们都不喜欢这个想法,因为我们都觉得向下转型是“邪恶的”。然而,没有人能准确解释为什么它是“邪恶的”。
在我们做出决定之前,我希望听到更多关于这些选项的评论。
最佳答案
http://en.wikipedia.org/wiki/Circle-ellipse_problem是你的第一个邪恶的例子。如果你发现你可以做一些违反基本原则的事情,那么你应该发明另一个轮子或尝试另一顶帽子:http://en.wikipedia.org/wiki/Six_Thinking_Hats
关于c++ - 在使用工厂模式时,我是否应该以任何方式避免向下转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6088411/
我一直在阅读有关汇编函数的内容,但对于是使用进入和退出还是仅使用调用/返回指令来快速执行,我感到很困惑。一种方式快而另一种方式更小吗?例如,在不内联函数的情况下,在汇编中执行此操作的最快(stdcal
我正在处理一个元组列表,如下所示: res = [('stori', 'JJ'), ('man', 'NN'), ('unnatur', 'JJ'), ('feel', 'NN'), ('pig',
最近我一直在做很多网络或 IO 绑定(bind)操作,使用线程有助于加快代码速度。我注意到我一直在一遍又一遍地编写这样的代码: threads = [] for machine, user, data
假设我有一个名为 user_stats 的资源,其中包含用户拥有的帖子、评论、喜欢和关注者的数量。是否有一种 RESTful 方式只询问该统计数据的一部分(即,对于 user_stats/3,请告诉我
我有一个简单的 api,它的工作原理是这样的: 用户创建一个请求 ( POST /requests ) 另一个用户检索所有请求 ( GET /requests ) 然后向请求添加报价 ( POST /
考虑以下 CDK Python 中的示例(对于这个问题,不需要 AWS 知识,这应该对基本上任何构建器模式都有效,我只是在这个示例中使用 CDK,因为我使用这个库遇到了这个问题。): from aws
Scala 中管理对象池的首选方法是什么? 我需要单线程创建和删除大规模对象(不需要同步)。在 C++ 中,我使用了静态对象数组。 在 Scala 中处理它的惯用和有效方法是什么? 最佳答案 我会把它
我有一个带有一些内置方法的类。这是该类的抽象示例: class Foo: def __init__(self): self.a = 0 self.b = 0
返回和检查方法执行的 Pythonic 方式 我目前在 python 代码中使用 golang 编码风格,决定移动 pythonic 方式 例子: import sys from typing imp
我正在开发一个 RESTful API。其中一个 URL 允许调用者通过 id 请求特定人员的记录。 返回该 id 不存在的记录的常规值是什么?服务器是否应该发回一个空对象或者一个 404,或者其他什
我正在使用 pathlib.Path() 检查文件是否存在,并使用 rasterio 将其作为图像打开. filename = pathlib.Path("./my_file-name.tif") 但
我正在寻找一种 Pythonic 方式来从列表和字典创建嵌套字典。以下两个语句产生相同的结果: a = [3, 4] b = {'a': 1, 'b': 2} c = dict(zip(b, a))
我有一个正在操裁剪理设备的脚本。设备有时会发生物理故障,当它发生时,我想重置设备并继续执行脚本。我有这个: while True: do_device_control() device
做组合别名的最pythonic和正确的方法是什么? 这是一个假设的场景: class House: def cleanup(self, arg1, arg2, kwarg1=False):
我正在开发一个小型客户端服务器程序来收集订单。我想以“REST(ful)方式”来做到这一点。 我想做的是: 收集所有订单行(产品和数量)并将完整订单发送到服务器 目前我看到有两种选择: 将每个订单行发
我知道在 Groovy 中您可以使用字符串调用类/对象上的方法。例如: Foo."get"(1) /* or */ String meth = "get" Foo."$meth"(1) 有没有办法
在 ECMAScript6 中,您可以使用扩展运算符来解构这样的对象 const {a, ...rest} = obj; 它将 obj 浅拷贝到 rest,不带属性 a。 有没有一种干净的方法可以在
我有几个函数返回数字或None。我希望我的包装函数返回第一个不是 None 的结果。除了下面的方法之外,还有其他方法吗? def func1(): return None def func2(
假设我想设计一个 REST api 来讨论歌曲、专辑和艺术家(实际上我就是这样做的,就像我之前的 1312414 个人一样)。 歌曲资源始终与其所属专辑相关联。相反,专辑资源与其包含的所有歌曲相关联。
这是我认为必须经常出现的问题,但我一直无法找到一个好的解决方案。假设我有一个函数,它可以作为参数传递一个开放资源(如文件或数据库连接对象),或者需要自己创建一个。如果函数需要自己打开文件,最佳实践通常
我是一名优秀的程序员,十分优秀!