首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >工厂方法模式与组成

工厂方法模式与组成
EN

Stack Overflow用户
提问于 2015-02-27 14:42:57
回答 4查看 2K关注 0票数 4

关于工厂方法模式的GoF章节:

定义用于创建对象的接口,但是让子类决定实例化的类。工厂方法允许类将实例化推迟到子类。

其思想是让子类决定要实例化哪个类,而GoF对该思想的实现是在超类中提供一个抽象方法,子类需要重写,从而提供自己的实例化逻辑。

我不明白的是,为什么要使用抽象方法来实现它,而不使用类成员(即工厂)。我来解释。

这是GoF的方式:

代码语言:javascript
复制
public abstract class Creator {
    public void doStuff() {
        Product product = createProduct();
        /* etc. */
    }

    public abstract Product createProduct();
}

用法:

代码语言:javascript
复制
    MyCreator myCreator = new Creator() {
        @Override
        public Product createProduct() {
            return new MyProduct();
        }
    }

    myCreator.doStuff();

但是为什么要费心子类等等呢?我建议这样做:

代码语言:javascript
复制
public class Creator {
    private Factory factory;

    /* constructor */
    public Creator(Factory factory) {
        this.factory = factory;
    }

    public void doStuff() {
        Product product = factory.createProduct();
        /* etc. */
    }
}

你就是这样用的:

代码语言:javascript
复制
    MyFactory myFactory = new MyFactory();
    Creator creator = new Creator(myFactory);
    creator.doStuff();

那么,GoF的方法有什么好处呢?为什么不将工厂组合到Creator类中,而不是使用抽象方法来表示它呢?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-02-27 15:01:05

为什么不将工厂组合到Creator类中,而不是使用抽象方法来表示它呢?

因为在这种情况下,客户端“知道”要实例化哪个Factory类,这违背了整个模式的目的。整个想法是,客户端不知道构建了什么工厂,它只调用一个抽象类。假设您将插件插入到您的框架中,一些第三方工厂提供程序,并且您不知道它们实例化了什么(也不关心),只要服务于这个目的。

票数 5
EN

Stack Overflow用户

发布于 2015-02-27 15:07:24

Factory方法模式用于赋予子类对它们生成的对象类型的控制权。在您的示例中,控制对象类型的不是子类,而是类的用户。

下面的示例是来自工厂方法模式上的Wikipedia条目的副本。我们有一个迷宫游戏,它存在两个变体:正常迷宫游戏和魔术迷宫游戏与适应规则。通常的迷宫游戏由正常的房间和魔术的迷宫游戏组成。

代码语言:javascript
复制
public class MazeGame {
    public MazeGame() {
        Room room1 = makeRoom();
        Room room2 = makeRoom();
        room1.connect(room2);
        this.addRoom(room1);
        this.addRoom(room2);
    }

    protected Room makeRoom() {
        return new OrdinaryRoom();
    }
}

public class MagicMazeGame extends MazeGame {
    @Override
    protected Room makeRoom() {
        return new MagicRoom();
    }
}

通过使用工厂方法模式,我们可以确保MagicMazeGame由MagicRooms组成,但我们仍然可以重用超类的部分。

在您的建议中,MazeGame类将更改为:

代码语言:javascript
复制
public class MazeGame {
    public MazeGame(RoomFactory factory) {
        Room room1 = factory.makeRoom();
        Room room2 = factory.makeRoom();
        room1.connect(room2);
        this.addRoom(room1);
        this.addRoom(room2);
    }
}

现在可以这样做:

代码语言:javascript
复制
MazeGame game1 = new MazeGame(new MagicRoomFactory());
MazeGame game2 = new MagicMazeGame(new OrdinaryRoomFactory());

这是您想要防止的事情,因为这样就可以创建带有错误房间的MazeGames。

票数 4
EN

Stack Overflow用户

发布于 2015-02-27 15:06:51

在这些类型的情况下,使用实际的英语类型作为插图而不是像“产品”这样更抽象的术语是非常有用的。

所以,让我们以宠物为例,说每一种宠物都有一个家。狗有一只犬类)。

以你为例,我们应该:

代码语言:javascript
复制
Public void doStuff() {
    Home home = factory.createHome();
}

但在这种情况下,说狗养狗,鸟养笼子的逻辑又在哪里呢?它必须进入工厂对象-这反过来意味着在工厂逻辑中必须显式地重复宠物的继承层次结构。这反过来意味着,每次添加新类型的宠物时,都必须记住将该类型添加到Factory中。

工厂方法模式意味着您将拥有如下内容:

代码语言:javascript
复制
public class Pet {
    private String name;
    private Home home;
    public Pet(String name) {
        this.name = name;
        this.home = this.createHome();
    }
    public abstract Home createHome();

这允许您每次创建新类型的宠物时,都可以指定宠物类型的主页,而不必更改任何其他类,并且在此过程中还知道每个宠物类型都有一个Home。

例如:你可能会:

代码语言:javascript
复制
public class Dog extends Pet {
    public Home createHome() {
        return new Kennel();
    }
}

编辑以添加Dog示例

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28767667

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档