工厂模式,另一种模式或根本没有模式?

时间:2011-06-30 23:45:17

标签: c# oop design-patterns factory-pattern

我有2个案例,一个方法可以被认为是工厂设计模式,这个例子是在C#中,altought,可以应用于其他编程语言:

enum NinjaTypes {
  Generic,
  Katanna,
  StarThrower,
  Invisible,
  Flyer
}

public class Ninja {
  public string Name { get; set; }
  public void jump() { ... }
  public void kickAss() { ... }
}

public class KatannaNinja: Ninja {
  public void useKatanna() { ... }
}

public class StarNinja: Ninja {
  public void throwStar() { ... }
}

public class InvisibleNinja: Ninja {
  public void becomeInvisible() {...}
  public void becomeVisible() {...}
}

public class FlyNinja: Ninja {
  public void fly() {...}
  public void land() {...}
}

public class NinjaSchool {
  // always return generic type
  public Ninja StandardStudent() {...}
  // may return other types
  public Ninja SpecialityStudent(NinjaTypes WhichType) {...}
}

方法StandardStudent()始终返回相同类型的新对象SpecialityStudent(...),可以从共享相同超类/基类型的不同类返回新对象。这两种方法都不是虚拟的。

问题是,两种方法都是“工厂设计模式”吗?

我的猜测是SpecialityStudent(...)是,但StandardStudent()不是。如果第二个不是,可以考虑另一种设计模式吗?

4 个答案:

答案 0 :(得分:3)

我认为,FactoryMethod`和AbstractFactory模式也不禁止用户使用参数为创建者方法指定类型。无论如何,你应该在设计中考虑至少两件事:

  1. 工厂方法有助于让客户端不知道所创建对象的具体类型。从我的观点来看,明确指定要创建的对象的类型并没有错,但要注意不要在客户端类上放置太多的知识,以便能够通过工厂构造对象。
  2. 你的工厂方法都返回一个Ninja对象,但是你的一些ninjas扩展类声明了其他方法,客户端并不知道。如果您的客户需要明确使用这些方法,那么您可能需要考虑一下您的设计。

答案 1 :(得分:2)

我认为这实际上看起来像一个反模式。没有什么可以阻止这个代码的消费者直接实例化专业忍者。使用忍者学校有什么好处?我认为Factory模式的重点是封装实例化对象的过程,以便您可以隐藏消费者的详细信息。每当你对“创建”逻辑进行更改时,它都不会破坏任何人的代码。 将所有类型都放在枚举中看起来是个坏主意。除了“感觉不对”之外,我没有具体理由支持这一主张。

在查看抽象工厂模式之后,我可以看到如何将其转换为抽象工厂,但我没有看到给定对象语义的好处。我认为,如果你想拥有一个Ninja工厂,你必须使个别构造函数受到保护或内部,所以它们不能被消费者代码直接调用

答案 2 :(得分:2)

您的方法都可以视为工厂。但第二个使用起来有点尴尬:

var school = new NinjaSchool();
var ninja = school.SpecialtyStudent(NinjaTypes.Flyer);
// to fly you must cast
((FlyingNinja)ninja).Fly();

你已经要求传单了,所以你不需要演员。一个更好的选择可能是消除枚举并要求你想要的确切忍者:

var flyingNinja = school.FlyingStudent(); // you get a FlyingNinja
flyingNinja.Fly();

在你的设计中要考虑的另一件事是:如果你想要一个可以飞的隐形忍者怎么办?还是一个还会抛出星星的武士刀忍者?这将改变您的层次结构并继承challenge your belief

答案 3 :(得分:0)

这几乎是一种工厂方法。我会做类似的事情:

enum NinjaTypes {
    Generic, Katanna, StarThrower, Invisible, Flyer
}

class Ninja {
String Name;

void jump() {
}

void kickAss() {
}

void useKatanna() {
    System.out.println("nothing happens");
}

void throwStar() {
    System.out.println("nothing happens");
}

void becomeInvisible() {
    System.out.println("nothing happens");
}

void becomeVisible() {
    System.out.println("nothing happens");
}

void fly() {
    System.out.println("nothing happens");
}

void land() {
    System.out.println("nothing happens");
}
}

class StarThrowerNinja extends Ninja {
    void throwStar() {
        System.out.println("throwing star");
    }
}

class NinjaSchool {
    static Ninja create(NinjaTypes WhichType) {
        switch (WhichType) {
        case Generic:
            return new Ninja();
        case StarThrower:
            return new StarThrowerNinja();
        default:
            return null;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Ninja generic=NinjaSchool.create(NinjaTypes.Generic);
        generic.throwStar();
        Ninja starThrower=NinjaSchool.create(NinjaTypes.StarThrower);
        starThrower.throwStar();
    }
}