来源于维基百科:什么时候工厂适合?
在面向对象的计算机编程 ,工厂是用于创建其他对象的对象 。它是一个 抽象的构造函数,并且可以使用 来实现各种 分配方案。
任何人都可以请解释何时需要或有利的工厂类?
我目前正在一个项目中,我有一个类,并使用构造函数来初始化一个对象(杜!),但它可以失败,并没有初始化。我有一个Success属性来检查它是否正确创建。这是什么时候应该实施工厂类的一个很好的例子?这样Create()方法可以返回null,我可以摆脱Success属性。我有正确的想法吗?
来源于维基百科:什么时候工厂适合?
在面向对象的计算机编程 ,工厂是用于创建其他对象的对象 。它是一个 抽象的构造函数,并且可以使用 来实现各种 分配方案。
任何人都可以请解释何时需要或有利的工厂类?
我目前正在一个项目中,我有一个类,并使用构造函数来初始化一个对象(杜!),但它可以失败,并没有初始化。我有一个Success属性来检查它是否正确创建。这是什么时候应该实施工厂类的一个很好的例子?这样Create()方法可以返回null,我可以摆脱Success属性。我有正确的想法吗?
工厂情况的教科书示例是当你有一个接口和几个实现,但你不想公开实现。您可以实现一个工厂(方法或类),该工厂根据您传递的参数生成不同实现的实例;但是,由于它通过接口类型返回它们,所以调用者不会因为实现细节而负担沉重。
真实世界的例子:假设你已经定义了一个流读取器的接口,以及从本地文件,网络资源和标准输入读取的实现。然后编写一个工厂方法,它接受一个参数(URI),并返回一个合适的阅读器。调用者不需要知道实现细节。最好的部分是,当你决定要支持另一种输入方法,比如data:URI时,你只需添加另一个实现并将其添加到工厂 - 你不需要在调用代码中改变任何东西。
一个工厂的目的是要确定,在运行时间,从而有可能和经常与不可用的数据时,该程序被编译,其中许多class
ES,都从virtual
方法的一个特定类派生的,应捕获数据你的程序。
问题是,多态语言功能允许您使用不同类型的数据(共享一个公共基类),调用类型适当的行为。为了从中受益,您需要具有不同派生类型的对象。在Comp Sci课程中学习这些知识时,可能需要硬编码创建每个Derived类型的一部分,并通过指向基类的指针与它们一起玩。在复杂的现实世界问题中,不是通过硬编码创建,而是通常从数据库表,文件和套接字等数据到达程序输入。根据您在每个点上看到的内容,您想要创建一个适当类型的对象来表示它,但您可能需要使用编译时间已知类型(指向基类的指针)记录它。然后,不仅可以执行基类承诺的操作 - 其中一些操作可能涉及动态分派到派生类的实现,但您还可以 - 如有必要 - 确切确定数据的实际类型,并据此调用操作。
例如,假设您阅读以下文件,这说明你是如何收集不同类型的数据的每个:
elephant name Tip-Toes partner Mega
mule name Dare-You mane_length 132
你有下面的类层次结构来表示这些:
struct Animal
{
Animal(const std::string& name) : name_(name) { }
virtual void eat_from(Supplies&) = 0; // animals must do in their own way...
virtual bool can_jump() { return false; } // some animals might, assume not...
std::string name_;
};
struct Elephant : Animal
{
Elephant(const std::string& name, const std::string& partner)
: Animal(name), partner_(partner)
{ }
std::string partner_;
virtual void eat_from(Supplies&) { supplies.consume(Tofu, 10 * kg); }
void swing_trunk(); // something specific to elephants
};
struct Mule : Animal
{
Mule(const std::string& name, double kgs) : Animal(name), kilograms_(kgs) { }
double kilograms_;
virtual void eat_from(Supplies&) { supplies.consume(Grass, 2 * kg); }
virtual bool can_jump() { return true; }
};
工厂方法的工作是区分大象与骡子并返回适当类型的新对象(衍生自 - 但不简单 - 动物):
Animal* factory(std::istringstream& input)
{
std::string what, name;
if (input >> what && input >> name)
{
if (what == "elephant")
{
std::string partner;
if (input >> partner)
return new Elephant(name, partner);
}
else if (what == "mule")
{
double mane_length;
if (input >> mane_length)
return new Mule(name, mane_length);
}
}
// can only reach here on unparsable input...
throw runtime_error("can't parse input");
}
然后,您可以储存动物* S并对其执行操作:
std::vector<Animal*> animals;
// we expect 30 animals...
for (int i = 0; i < 30; ++i) animals.push_back(factory(std::cin));
// do things to each animal...
for (int i = 0; i < 30; ++i)
{
Animal* p_unknown = animals[i];
std::cout << p_unknown->name() << '\n';
if (Elephant* p = dynamic_cast<Elephant*>(p_unknown))
p->swing_trunk();
}
回到你的问题:
我目前工作的一个项目,我有一个类,并使用构造函数初始化一个对象(Duh!),但它可能会失败并且根本不初始化。我有一个Success属性来检查它是否正确创建。这是什么时候应该实施工厂类的一个很好的例子?这样Create()方法可以返回null,我可以摆脱Success属性。我有正确的想法吗?
不,不是工厂有用的情况,因为只涉及一种类型。只要坚持你所拥有的东西(按照OO的意义),但你可以选择抛出异常,中止程序等,而不是设置被调用者可能会或可能不会检查的标志。
很好的答案,因子方法和工厂类有区别吗? – 2012-01-28 10:02:12
“方法”只是“功能”的另一个名称,明确的功能可以放在一个类中,以便将它们可能需要的任何数据和支持功能组合在一起 - 然后你有一个工厂类,但它并不真正改变事物的方式正在工作 - 只是更好地封装它。当你有一个抽象工厂类时,这意味着工厂函数(和/或支持代码)可以是'虚拟的',并且可以调用任何几个工厂实现,这会变得更有趣 - 并且有意义的不同。例如,选择一个“XML解析”vs“JSON解析”工厂,然后使用。 – 2012-01-31 01:05:31
我对工厂模式的看法一直有所不同,但我会无论如何给它。
A工厂用于创建一组相关的类型。相关并不意味着它们必须完全实现相同的接口。相关意思是如果你需要实例化一个类型,然后你需要创建另一个对象,第二个对象的具体(实现)类型取决于第一个对象的具体类型,那么你需要一个Factory。
只创建一种类型的对象(没有“关联性”)的工厂不是工厂,而更像是一个策略。
我上面的定义意味着工厂不会像您想象的那样被使用或需要。
而对于无法初始化的对象,我推荐通过抛出异常而不是依赖状态字段的快速失败方法。
我会尝试一个简单的答案:)
时,使用工厂模式。
所以我认为你不需要在你的特定情况下工厂。但我会说有一个不伤害。
如果你想返回一个接口并隐藏实现类,那么工厂通常会使用它。
例如:
public final class LoginFactory {
private final static Map<SomeEnum, LoginInterface> IMPLEMENTERS = new HashMap<SomeEnum, LoginInterface>();
static {
IMPLEMENTERS.put(SomeEnum.QUICK, new QuickerLoginImpl());
IMPLEMENTERS.put(SomeEnum.SECURE, new SecureLoginImpl());
}
public static LoginInterface getLoginImpl(SomeEnum type) { // my naming is bad ...
return IMPLEMENTERS.get(type);
}
}
这样你就可以改变你的SecureLoginImpl
到MoreSecureLoginImpl
例如没有你的API的用户甚至没有注意到。
你可能也想看看这个维基页面Abstract Factory pattern。
工厂类或工厂方法? – Bozho 2010-11-30 10:00:55