工厂设计模式和关键字'新'

时间:2011-12-31 21:45:12

标签: oop design-patterns

我是一名初学程序员。我知道OOP的基础知识,但我不知道"最佳实践"还没。例如,一个继续出现在编程中的范例是"抽象工厂"设计模式,看起来相当简单。其背后的关键意图之一是避免使用关键字" new",因为它被认为是有害的。我在编程课程中从未听过这个。有人可以详细阐述这一点吗?为什么我们要避免以这种形式实例化对象?

6 个答案:

答案 0 :(得分:9)

在您编写的客户端/调用者类中考虑:

Vehicle v = new Car("BMW");

如果您的代码与上面的代码类似,您将始终获得一辆汽车。将来,如果你真的想要一架飞机,你将不得不更新客户代码。

或者,您使用工厂模式,您的代码如下:

Vehicle v = Factory.getVehicle();

现在,您可以保持从客户端离开车辆(松耦合)的逻辑,如果您必须更新您获得的最终车辆,您的客户将永远不需要更改。只有Factory实施将更新,您的客户将按原样运行。

答案 1 :(得分:4)

我不会说new被认为是有害的。抽象工厂模式尝试做的是解决new不可重写的问题(即与虚拟调度不兼容,至少在Java和C#等语言中)。

考虑这个示例代码(C#):

class Sender
{
    private ISendChannel channel;

    public Sender()
    {
    }

    public void Connect(Uri endpointAddress)
    {
        // !! Sender is tightly coupled to TCP implementation
        // !! even though it doesn't apparently have to be.
        this.channel = new TcpSendChannel(endpointAddress);
    }

    /* ... */
}

在此代码中,我们有一个基接口ISendChannel,允许向某个端点进行前向通信。但是,给定的实现被固定为始终使用TCP信道,无论如何。这是不可取的,因为现在如果您想要HTTP发送者,您必须修改Sender类或向其添加新方法。这是“坏耦合”。

相反,您可以使用工厂创建频道并将其传递给发件人。发件人将要求工厂创建频道,从而放弃该责任。新的实现可能如下所示:

class Sender
{
    private readonly ISendChannelFactory factory;
    private ISendChannel channel;

    public Sender(ISendChannelFactory factory)
    {
        this.factory = factory;
    }

    public void Connect(Uri endpointAddress)
    {
        // Sender does not have to care what type of channel it is.
        this.channel = this.factory.CreateSendChannel(endpointAddress);
    }

    /* ... */
}

现在要使用HTTP通道,您可以使用不同的工厂类型实例化发件人,例如new Sender(new HttpSendChannelFactory(/* ... */));。然后,HttpSendChannelFactory可以从HttpSendChannel方法返回ISendChannel(来自CreateSendChannel的具体类型)。

答案 2 :(得分:4)

我建议您阅读这篇文章:http://www.codinghorror.com/blog/2005/09/head-first-design-patterns.html

关键部分是:学习编写简单代码的最好方法是编写简单的代码!应该避免使用各种复杂形式的模式,直到它们是绝对必要的。这是初学者需要学习的第一件事。不是最后一件事。

我同意 - 只有在真的需要它时才需要工厂。

好的,回到主题,关键字new可能是邪恶的,但在大多数情况下,肯定不是也不应该是令人头疼的问题。看到了

List <Person> persons = new ArrayList<Person>();

完全没问题。甚至不敢考虑工厂生产ArrayListLinkedList。那将是完全过度设计的。

我见过很多系统,其中Factory模式被过度使用。例如,如果系统中的每个对象都是使用Factory创建的,而不是直接实例化(例如,new StringNode(ノ)) ,该系统可能拥有过多的工厂。“@ Joshua Kerievsky

除非你确定它是个好主意,否则不要过早添加模式,如果没有足够的经验你就无法确定。开始用你脑海中的模式编写代码 - 种类:工厂,这很棒,让我们看看何时可以放置它! - 这不是一个好主意:)。更好的方法是在代码中的地方添加模式很麻烦,当你觉得(气味:) - 代码味道)这可以以某种方式更好地完成。那就是重构模式

有一本很棒的书,我会给你链接到“将创作知识转移到工厂”这一章

http://www.informit.com/articles/article.aspx?p=1398606&seqNum=2

我知道它很长,但请仔细阅读,这肯定值得付出努力

答案 3 :(得分:1)

要理解这种模式或使用new关键字有什么问题,您缺少必要的先决条件编程范例Programming against an interface

研究这个,一旦你理解它是什么,你就会明白,真正强制执行/遵循它的唯一方法是避免在你的代码中使用new,即明确地在你的代码中实例化具体对象令人讨厌的代码耦合效应。

答案 4 :(得分:0)

抽象工厂模式的想法不是要了解包括构造函数在内的具体实现。

因此标准的Factory模式将返回一个具体的类,例如

SomeType SomeVar = SomeFactory.CreateSomeType();

抽象工厂模式将在哪里

SomeInterface SomeVar = AbstractFactory.CreateSomeInterface();

因此,不是SomeType暴露给消费者,而是只有接口。只是更高级别的抽象,这是有用的,但只有在您不希望工厂消费者必须了解SomeType时才有害。

答案 5 :(得分:-1)

据我所知,new关键字没有任何问题。 我正在谈论PHP开发人员。新关键字没有任何问题,也没有一些安全问题。

PHP中的工厂模式用于自动要求,生成类的实例,并返回该类。不是因为new关键字有问题,但是要运行一个静态函数要快得多,然后要求并为你需要的每个对象使用new关键字。

在后台你无论如何都会使用新关键字:)

新的没有错,没有必要避免它。它与工厂模式相比,它更快地获得类实例然后需要类,然后用新关键字实现它。