- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我最近听说了抽象工厂模式,目前对在需要参数化构造函数时如何设计这种模式有一些疑问。
更准确地说,据我了解,这种设计模式的主要好处之一是为了便于代码管理,因为每当向系统引入一种新类型时,都需要调整一个调用对象构造函数的工厂函数。
我发现的大多数示例仅考虑空构造函数(比如默认构造函数)。
但是,如果需要使用参数化构造函数会怎样?这种设计模式还有效吗?
由于派生类之间的参数类型和数量可能不同,是否需要考虑多个工厂功能?下面我将举例说明我想要实现的目标。请注意,为了减少代码行,我只考虑了每个类一个构造函数,它既用作默认构造函数又用作参数化构造函数。
class Shape {
public:
Shape(){std::cout << "Calling Shape Constructor\n";};
virtual ~Shape(){std::cout << "Calling Shape Desstructor\n";};
virtual void draw() const = 0;
virtual void doSomething1(int) const = 0;
virtual void doSomething2(int, float) const = 0;
};
class Rectangle : public Shape {
public:
Rectangle(int l = 0, int b = 0 ):l(l),b(b){ std::cout << "Calling Rectangle Constructor\n"; };
~Rectangle(){ std::cout << "Calling Rectangle Destructor\n\n"; };
virtual void draw() const{ /* Draw Rectangle */ };
virtual void doSomething1(int) const { /* doSomething1 */};
virtual void doSomething2(int, float) const { /* doSomething2 */};
private:
int l,b;
};
class Circle : public Shape {
public:
Circle(int r = 0):r(r){ std::cout << "Calling Circle Constructor\n"; };
~Circle(){ std::cout << "Calling Rectangle Destructor\n\n"; };
virtual void draw() const{ /* Draw Circle*/ };
virtual void doSomething1(int) const { /* doSomething1 */};
virtual void doSomething2(int, float) const { /* doSomething2 */};
private:
int r;
};
class ShapeFactory{
public:
ShapeFactory(int = 0, double = 0);
std::unique_ptr<Shape> CreateShape(const std::string & );
~ShapeFactory();
};
std::unique_ptr<Shape> ShapeFactory::CreateShape(const std::string & type /*, int rad, int side1, int side2, .... */) {
if ( type == "circle" ) return std::unique_ptr<Shape>(new Circle( /* rad */)); // Should call Circle(int rad)!
if ( type == "rectangle" ) return std::unique_ptr<Shape>(new Rectangle( /* side1, side2 */)); // Should call Rectangle(int, int)!
// if ( type == "someNewShape") return std::unique_ptr<Shape>(new someNewShape( /* param1, param2, ... */)); // Should call someNewShape(param1, param2)!
throw std::invalid_argument("MobileFactory: invalid type: " + type);
}
我还有一个疑问。想象一下,由于某些需要,我需要“ShapeFactory”类的类成员。我想凭直觉做的是:
std::vector< std::unique_ptr<ShapeFactory2> > mylist;
mylist.push_back( new ShapeFactory2(CreateShape("circle",radius), param1, param2) );
mylist.push_back( new ShapeFactory2(CreateShape("rectangle",side1,side2), param1, param2) );
for (std::vector< std::unique_ptr<ShapeFactory2> >::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
{
int param1 = it->param1;
float param2 = it->param2;
it->doSomething2(param1, param2);
// or equivalently
Shape * myShape = *it;
int param1 = it->param1;
float param2 = it->param2;
myShape->doSomething2(param1, param2);
}
对于这种特定情况,“ShapeFactory”类声明会发生什么变化?除了 param1、param2 之外,我现在还会有一个 smart_pointer 作为类(class)成员吗?如果是,谁能说明如何实现构造函数/析构函数?
非常欢迎所有建议/想法! ;-)
最佳答案
只有当派生对象的签名足够相似以支持公共(public)构造函数签名时,工厂模式才真正适用。这是一种常见的情况,因为对象适合共享虚函数签名,因此构造函数也相似。在您的示例中,从中心点和区域构建形状适合工厂模式。
如果构造函数完全不同,工厂模式就毫无意义,应该避免使用。当不使用工厂时,您提供的用法示例更加清晰和安全。
我将使用我最近代码中的参数为您提供一个合理的工厂的简短示例:假设您想要将一个函数拟合到图像的像素。有两种可能的计算方式,不相交(行和列彼此分开)和 union 。不相交拟合更便宜,但对于某些数据来说是不可能的。这些计算方式由两个不同的类支持,DisjointFitter 和 JointFitter,它们接收数据作为它们的参数并且都派生自 Fitter。工厂看起来像:
std::auto_ptr<Fitter> Fitter::create( const Data& data ) {
if ( data.supports_disjoint_fitting() ) {
return std::auto_ptr<Fitter>( new DisjointFitter(data) );
} else {
return std::auto_ptr<Fitter>( new JointFitter(data) );
}
}
在形状上有些做作的术语中,它可能看起来像:
enum BasicShape { Round, Edgy };
mylist.push_back( ShapeFactory::CreateShape( Round, 16 ) );
抽象工厂方法看起来像:
static std::unique_ptr<Shape> CreateShape(BasicShape shape, double area) {
if ( shape == Round )
return std::unique_ptr<Shape>( new Circle( sqrt(area / M_PI) ) );
else
return std::unique_ptr<Shape>( new Square( sqrt(area) ) );
}
关于c++ - 具有参数化构造函数的抽象工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8287441/
简而言之:我想从可变参数模板参数中提取各种选项,但不仅通过标签而且通过那些参数的索引,这些参数是未知的 标签。我喜欢 boost 中的方法(例如 heap 或 lockfree 策略),但想让它与 S
我可以对单元格中的 excel IF 语句提供一些帮助吗? 它在做什么? 对“BaselineAmount”进行了哪些评估? =IF(BaselineAmount, (Variance/Baselin
我正在使用以下方法: public async Task Save(Foo foo,out int param) { ....... MySqlParameter prmparamID
我正在使用 CodeGear RAD Studio IDE。 为了使用命令行参数测试我的应用程序,我多次使用了“运行 -> 参数”菜单中的“参数”字段。 但是每次我给它提供一个新值时,它都无法从“下拉
我已经为信用卡类编写了一些代码,粘贴在下面。我有一个接受上述变量的构造函数,并且正在研究一些方法将这些变量格式化为字符串,以便最终输出将类似于 号码:1234 5678 9012 3456 截止日期:
MySql IN 参数 - 在存储过程中使用时,VarChar IN 参数 val 是否需要单引号? 我已经像平常一样创建了经典 ASP 代码,但我没有更新该列。 我需要引用 VarChar 参数吗?
给出了下面的开始,但似乎不知道如何完成它。本质上,如果我调用 myTest([one, Two, Three], 2); 它应该返回元素 third。必须使用for循环来找到我的解决方案。 funct
将 1113355579999 作为参数传递时,该值在函数内部变为 959050335。 调用(main.c): printf("%d\n", FindCommonDigit(111335557999
这个问题在这里已经有了答案: Is Java "pass-by-reference" or "pass-by-value"? (92 个回答) 关闭9年前。 public class StackOve
我真的很困惑,当像 1 == scanf("%lg", &entry) 交换为 scanf("%lg", &entry) == 1 没有区别。我的实验书上说的是前者,而我觉得后者是可以理解的。 1 =
我正在尝试使用调用 SetupDiGetDeviceRegistryProperty 的函数使用德尔福 7。该调用来自示例函数 SetupEnumAvailableComPorts .它看起来像这样:
我需要在现有项目上实现一些事件的显示。我无法更改数据库结构。 在我的 Controller 中,我(从 ajax 请求)传递了一个时间戳,并且我需要显示之前的 8 个事件。因此,如果时间戳是(转换后)
rails 新手。按照多态关联的教程,我遇到了这个以在create 和destroy 中设置@client。 @client = Client.find(params[:client_id] || p
通过将 VM 参数设置为 -Xmx1024m,我能够通过 Eclipse 运行 Java 程序-Xms256M。现在我想通过 Windows 中的 .bat 文件运行相同的 Java 程序 (jar)
我有一个 Delphi DLL,它在被 Delphi 应用程序调用时工作并导出声明为的方法: Procedure ProduceOutput(request,inputs:widestring; va
浏览完文档和示例后,我还没有弄清楚 schema.yaml 文件中的参数到底用在哪里。 在此处使用 AWS 代码示例:https://github.com/aws-samples/aws-proton
程序参数: procedure get_user_profile ( i_attuid in ras_user.attuid%type, i_data_group in data_g
我有一个字符串作为参数传递给我的存储过程。 dim AgentString as String = " 'test1', 'test2', 'test3' " 我想在 IN 中使用该参数声明。 AND
这个问题已经有答案了: When should I use "this" in a class? (17 个回答) 已关闭 6 年前。 我运行了一些java代码,我看到了一些我不太明白的东西。为什么下
我输入 scroll(0,10,200,10);但是当它运行时,它会传递字符串“xxpos”或“yypos”,我确实在没有撇号的情况下尝试过,但它就是行不通。 scroll = function(xp
我是一名优秀的程序员,十分优秀!