Заводская модель, другая модель или нет модели вообще? - PullRequest
8 голосов
/ 01 июля 2011

У меня есть 2 случая, когда метод может считаться шаблоном Factory Design, этот пример на C #, может применяться к другим языкам программирования:

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(...), может возвращать новые объекты из разных классов, которые имеют один и тот же суперкласс / базовый тип. Оба метода намеренно не являются виртуальными.

Вопрос в том, являются ли оба метода "Factory Design Pattern"?

Я предполагаю, что SpecialityStudent(...) есть, а StandardStudent() нет. Если второго нет, можно ли считать другой шаблон дизайна?

Ответы [ 4 ]

3 голосов
/ 01 июля 2011

Я не думаю, что ни шаблоны FactoryMethod `, ни AbstractFactory запрещают пользователю использовать параметр для указания типа для метода создателя. В любом случае, вы должны учитывать как минимум 2 вещи в своем дизайне:

  1. Фабричные методы полезны для того, чтобы клиент не знал о конкретном типе создаваемого объекта. С моей точки зрения, неправильно указывать явно тип создаваемого объекта, но обратите внимание на то, чтобы не навязывать слишком много знаний клиентским классам, чтобы иметь возможность конструировать объекты с помощью фабрики.
  2. Оба ваших фабричных метода возвращают объект Ninja, но некоторые из вашего расширенного класса ninjas объявляют дополнительные методы, о которых клиент не знает. Если вашему клиенту нужно явно использовать эти методы, возможно, вам стоит подумать над своим дизайном.
2 голосов
/ 01 июля 2011

Оба ваших метода можно рассматривать как фабрики.Но второе немного неудобно в использовании:

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();

Еще одна вещь, которую следует учитывать в вашем дизайне, заключается в следующем: что если вы хотите, чтобы невидимый ниндзя мог летать?Или катана ниндзя, который также бросает звезды?Это встряхнет вашу иерархию и поставит под сомнение вашу веру в наследство.

2 голосов
/ 01 июля 2011

Я думаю, что на самом деле это выглядит как анти-паттерн. Нет ничего, что могло бы помешать потребителю этого кода просто создать экземпляр специальности ниндзя. Какая польза от использования школы ниндзя? Я думаю, что весь смысл фабричного паттерна заключается в инкапсуляции процесса создания объекта, чтобы вы могли скрыть детали от потребителя. Каждый раз, когда вы вносите изменения в логику «создания», она не нарушает чей-либо код. И это просто плохая идея иметь все типы в перечислении. У меня нет конкретной причины подкреплять это утверждение, кроме слов «это неправильно».

После просмотра шаблона Абстрактной фабрики я вижу, как можно превратить это в Абстрактную фабрику, но я не вижу выгоды, учитывая семантику ваших объектов. Я думаю, что если вы хотите иметь фабрику ниндзя, вам нужно сделать отдельные конструкторы защищенными или внутренними, чтобы их нельзя было вызывать напрямую из кода потребителя

0 голосов
/ 01 июля 2011

Это почти заводской метод.Я бы сделал что-то вроде:

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();
    }
}
...