工厂模式中的传值
Passing value in factory pattern
我正在学习工厂设计模式。我不知道如何将参数传递给使用工厂模式创建的对象。
一个愚蠢的小例子:
假设我有三个 class、Class A
和 class B
以及 Class Number
。 Number
是 base class
。此外,class A 需要三个整数并具有将它们相加的功能,class B 需要两个整数并将它们相加
代码片段:
int main()
{
Factory *facObj = new Factory();
// Addition for Two Integers
Number * numberObjOne = facObj->createObj("AddThreeInteger");
Number * numberObjTwo = facObj->createObj("AddTwoInteger");
}
Factory.cpp
Number * Factory::createObj(string str)
{
if (str == "AddThreeInteger")
{
return new A(1,2,3);
}
else if (str == "AddTwoInteger")
{
return new B(1,2);
}
else
return NULL;
}
问题:现在无论我做什么我都只能添加硬编码的数字。如何从我的客户端代码或 main() 传递这些整数值。这是一个愚蠢的例子,我是编程新手。请在这里帮助我。我怎么能不对值进行硬编码并获得结果呢。我可以通过某种方式传递 facObj->createObj
处的值吗?我说得通吗?请帮助我。
我不是设计模式方面的专家。所以我不确定下面的建议是否仍然兼容工厂模式。
一种方法是创建不同的方法,例如 CreateObjectA(int a, int b, int c)
和 CreateObjectB(int a, int b)
。另一种选择是将 std::vector<int>
添加到您的方法 createObj
中。如果所有 类 A、B、... 的整数个数不同,则向量的长度可用于决定创建哪个对象。如果这是不可能的,你可以,例如使用某种 ID 告诉工厂要创建哪个对象。
有很多方法可以做到。
一种方法是在您的工厂中使用单独的创建方法来构建每个子classes。每个创建方法都会为它构造的 subclass 获取适当的参数,并将它们相应地转发给 subclass 的构造函数。
另一种方法是使用单独的 "parameters" class 以某种方式定义所创建对象的参数。它将允许指定这些参数。对于这种情况,std::vector
是合适的。然后,您的 create() 方法必须验证传递的参数是否有效,否则会抛出异常,或者类似的东西。
选项 1
您可以使用模板概括您的工厂 class。
例如,您可以将要构造的类型发送给工厂。
这是一个示例,说明您的案例可能的解决方案:
struct Factory {
template<typename T, typename... Args>
T create(Args&&... args) {
return T{1, 2, std::forward<Args>(args)...};
}
};
会这样使用:
Factory factory;
auto myA = factory.create<A>(1, 2, "an additional char* parameter");
// no additional parameter works too
auto myB = factory.create<B>();
嗯,这个 class 很简单。它构造了一个类型 T
,参数为 Args
,外加两个 int 参数。但是它不允许根据字符串的值制作不同的类型。
顺便说一下,您应该将代码中的每个 new
替换为 std::make_unique
,那里的代码中存在大量内存泄漏。或者,您可以创建堆栈的对象。
选项 2
如果您知道根据您发送的参数构造什么类型,您可以重载您的函数。
这是它的样子:
struct Factory {
A create(int a, int b, int c) {
return A{a, b, c};
}
B create(int a, int b) {
return B{a, b};
}
};
你可以这样使用它:
Factory factory;
auto myA = factory.create(1, 2, 3);
auto myB = factory.create(1, 2);
这可能更容易实施。但请注意,您将无法拥有一个带有两个构造函数的 class,您也无法拥有两个具有相同参数的 class。
完整的、可运行的示例。 c++11 或更高版本。
注意 unique_ptr 的用法。不要使用原始指针。
#include <iostream>
#include <memory>
#include <stdexcept>
#include <exception>
#include <utility>
template<class T, class...Args>
struct creatable_from {
template<class X, class...Ys>
static auto test(int) -> decltype(X(std::declval<Ys>()...), void(), std::true_type());
template<class X, class...Ys>
static auto test(...) -> decltype(std::false_type());
static constexpr auto value = decltype(test<T, Args...>(0))::value;
};
struct Operation {
virtual ~Operation() = default;
virtual int operator()() const = 0;
};
struct Add : Operation
{
Add(int x, int y)
: x(x), y(y)
{}
int operator()() const override {
return x + y;
}
int x, y;
};
struct Sub : Operation
{
Sub(int x, int y)
: x(x), y(y)
{}
int operator()() const override {
return x - y;
}
int x, y;
};
struct AddSub : Operation
{
AddSub(int x, int y, int z)
: x(x), y(y), z(z)
{}
int operator()() const override {
return x + y - z;
}
int x, y, z;
};
struct Factory
{
template<class...Args>
std::unique_ptr<Operation> create(const std::string& type, Args&&...args)
{
if (type == "Add") {
return do_create<Add>(std::forward<Args>(args)...);
}
if (type == "Sub") {
return do_create<Sub>(std::forward<Args>(args)...);
}
if (type == "AddSub") {
return do_create<AddSub>(std::forward<Args>(args)...);
}
// default - return a null pointer, but would probably be better to
// throw a logic_error
return {};
}
private:
template<class T, class...Args>
static auto do_create(Args&&...args)
-> std::enable_if_t< creatable_from<T, Args...>::value, std::unique_ptr<T> >
{
return std::make_unique<T>(std::forward<Args>(args)...);
}
template<class T, class...Args>
static auto do_create(Args&&...args)
-> std::enable_if_t< not creatable_from<T, Args...>::value, std::unique_ptr<T> >
{
throw std::invalid_argument("wrong number of arguments");
}
};
int main()
{
auto facObj = Factory();
auto t1 = facObj.create("Add", 2, 3);
auto t2 = facObj.create("Sub", 3, 2);
auto t3 = facObj.create("AddSub", 2, 3, 4);
std::cout << (*t1)() << std::endl;
std::cout << (*t2)() << std::endl;
std::cout << (*t3)() << std::endl;
}
预期输出:
5
1
1
我正在学习工厂设计模式。我不知道如何将参数传递给使用工厂模式创建的对象。
一个愚蠢的小例子:
假设我有三个 class、Class A
和 class B
以及 Class Number
。 Number
是 base class
。此外,class A 需要三个整数并具有将它们相加的功能,class B 需要两个整数并将它们相加
代码片段:
int main()
{
Factory *facObj = new Factory();
// Addition for Two Integers
Number * numberObjOne = facObj->createObj("AddThreeInteger");
Number * numberObjTwo = facObj->createObj("AddTwoInteger");
}
Factory.cpp
Number * Factory::createObj(string str)
{
if (str == "AddThreeInteger")
{
return new A(1,2,3);
}
else if (str == "AddTwoInteger")
{
return new B(1,2);
}
else
return NULL;
}
问题:现在无论我做什么我都只能添加硬编码的数字。如何从我的客户端代码或 main() 传递这些整数值。这是一个愚蠢的例子,我是编程新手。请在这里帮助我。我怎么能不对值进行硬编码并获得结果呢。我可以通过某种方式传递 facObj->createObj
处的值吗?我说得通吗?请帮助我。
我不是设计模式方面的专家。所以我不确定下面的建议是否仍然兼容工厂模式。
一种方法是创建不同的方法,例如 CreateObjectA(int a, int b, int c)
和 CreateObjectB(int a, int b)
。另一种选择是将 std::vector<int>
添加到您的方法 createObj
中。如果所有 类 A、B、... 的整数个数不同,则向量的长度可用于决定创建哪个对象。如果这是不可能的,你可以,例如使用某种 ID 告诉工厂要创建哪个对象。
有很多方法可以做到。
一种方法是在您的工厂中使用单独的创建方法来构建每个子classes。每个创建方法都会为它构造的 subclass 获取适当的参数,并将它们相应地转发给 subclass 的构造函数。
另一种方法是使用单独的 "parameters" class 以某种方式定义所创建对象的参数。它将允许指定这些参数。对于这种情况,std::vector
是合适的。然后,您的 create() 方法必须验证传递的参数是否有效,否则会抛出异常,或者类似的东西。
选项 1
您可以使用模板概括您的工厂 class。
例如,您可以将要构造的类型发送给工厂。
这是一个示例,说明您的案例可能的解决方案:
struct Factory {
template<typename T, typename... Args>
T create(Args&&... args) {
return T{1, 2, std::forward<Args>(args)...};
}
};
会这样使用:
Factory factory;
auto myA = factory.create<A>(1, 2, "an additional char* parameter");
// no additional parameter works too
auto myB = factory.create<B>();
嗯,这个 class 很简单。它构造了一个类型 T
,参数为 Args
,外加两个 int 参数。但是它不允许根据字符串的值制作不同的类型。
顺便说一下,您应该将代码中的每个 new
替换为 std::make_unique
,那里的代码中存在大量内存泄漏。或者,您可以创建堆栈的对象。
选项 2
如果您知道根据您发送的参数构造什么类型,您可以重载您的函数。
这是它的样子:
struct Factory {
A create(int a, int b, int c) {
return A{a, b, c};
}
B create(int a, int b) {
return B{a, b};
}
};
你可以这样使用它:
Factory factory;
auto myA = factory.create(1, 2, 3);
auto myB = factory.create(1, 2);
这可能更容易实施。但请注意,您将无法拥有一个带有两个构造函数的 class,您也无法拥有两个具有相同参数的 class。
完整的、可运行的示例。 c++11 或更高版本。
注意 unique_ptr 的用法。不要使用原始指针。
#include <iostream>
#include <memory>
#include <stdexcept>
#include <exception>
#include <utility>
template<class T, class...Args>
struct creatable_from {
template<class X, class...Ys>
static auto test(int) -> decltype(X(std::declval<Ys>()...), void(), std::true_type());
template<class X, class...Ys>
static auto test(...) -> decltype(std::false_type());
static constexpr auto value = decltype(test<T, Args...>(0))::value;
};
struct Operation {
virtual ~Operation() = default;
virtual int operator()() const = 0;
};
struct Add : Operation
{
Add(int x, int y)
: x(x), y(y)
{}
int operator()() const override {
return x + y;
}
int x, y;
};
struct Sub : Operation
{
Sub(int x, int y)
: x(x), y(y)
{}
int operator()() const override {
return x - y;
}
int x, y;
};
struct AddSub : Operation
{
AddSub(int x, int y, int z)
: x(x), y(y), z(z)
{}
int operator()() const override {
return x + y - z;
}
int x, y, z;
};
struct Factory
{
template<class...Args>
std::unique_ptr<Operation> create(const std::string& type, Args&&...args)
{
if (type == "Add") {
return do_create<Add>(std::forward<Args>(args)...);
}
if (type == "Sub") {
return do_create<Sub>(std::forward<Args>(args)...);
}
if (type == "AddSub") {
return do_create<AddSub>(std::forward<Args>(args)...);
}
// default - return a null pointer, but would probably be better to
// throw a logic_error
return {};
}
private:
template<class T, class...Args>
static auto do_create(Args&&...args)
-> std::enable_if_t< creatable_from<T, Args...>::value, std::unique_ptr<T> >
{
return std::make_unique<T>(std::forward<Args>(args)...);
}
template<class T, class...Args>
static auto do_create(Args&&...args)
-> std::enable_if_t< not creatable_from<T, Args...>::value, std::unique_ptr<T> >
{
throw std::invalid_argument("wrong number of arguments");
}
};
int main()
{
auto facObj = Factory();
auto t1 = facObj.create("Add", 2, 3);
auto t2 = facObj.create("Sub", 3, 2);
auto t3 = facObj.create("AddSub", 2, 3, 4);
std::cout << (*t1)() << std::endl;
std::cout << (*t2)() << std::endl;
std::cout << (*t3)() << std::endl;
}
预期输出:
5
1
1