2015-10-28 4 views
1

В настоящее время я разрабатываю приложение с большим количеством различных шаблонов дизайна. Он должен следовать хорошей практике, в принципе код не пахнет.Слишком много, если заявления внутри фабрики

Я использую фабричный метод для печати случайных типов объектов, но мне нужно использовать утверждения 3 if, которые кажутся неэффективными ... Что произойдет, если я захочу распечатать 10 разных объектов? Было бы просто добавить больше, если бы не было другого пути.

** Конечным использованием данного метода на заводе является просто возврат случайного объекта (1) типа шара.

RandomGenerator ranGen = new RandomGenerator(); 
int randomNumber = ranGen.createRandomNumber(1,3); 
if(randomNumber == 1){ 
    //return smallBall 
} 
else if(randomNumber ==2){ 
    //return mediumBall 
} 
else if(randomNumber == 3){ 
    //return largeBall 
} 
+1

Даже выключатель был бы повторить несколько раз? –

+2

Вы также можете создать массив разных шаров и использовать случайное число для индекса. – azurefrog

+0

Какими данными ваш бал? –

ответ

3

Другим подходом было бы применение prototype pattern.

В следующем примере у нас есть класс с именем RandomBallFactory, который создает случайные (уникальные) экземпляры Ball путем клонирования зарегистрированных прототипов.

Преимущества:

  • Мы можем добавлять новые Ball подклассы без необходимости изменения RandomBallFactory реализации.
  • Мы можем создавать объекты того же типа, но с разными параметрами.
  • У нас нет утверждений if.

Java пример:

import java.util.*; 

abstract class Ball implements Cloneable { 
    abstract String getName(); 
    public Ball clone() { 
     Ball ball; 
     try { 
      ball = (Ball)super.clone(); 
     } catch (CloneNotSupportedException e) { 
      ball = null; 
     } 
     return ball; 
    } 
} 

class SmallBall extends Ball { 
    public String getName() { return "smallBall"; } 
} 

class MediumBall extends Ball { 
    public String getName() { return "mediumBall"; } 
} 

class LargeBall extends Ball { 
    public String getName() { return "largeBall"; } 
} 

class RandomBallFactory { 
    private final List<Ball> prototypes; 

    public RandomBallFactory() { 
     prototypes = new ArrayList<Ball>(); 
    } 

    public void registerBall(Ball ball) { 
     prototypes.add(ball); 
    } 

    public Ball createBall() { 
     Random randomGenerator = new Random(); 
     Integer randomNumber = randomGenerator.nextInt(prototypes.size()); 
     return prototypes.get(randomNumber).clone(); 
    } 
} 

public class TestBalls { 
    public static void main(String[] args) { 
     RandomBallFactory randomBallFactory = new RandomBallFactory(); 
     randomBallFactory.registerBall(new SmallBall()); 
     randomBallFactory.registerBall(new MediumBall()); 
     randomBallFactory.registerBall(new LargeBall()); 

     Ball ball = randomBallFactory.createBall(); 
     System.out.println(ball.getName()); 
    } 
} 

C++ пример:

#include <iostream> 
#include <vector> 
#include <memory> 
#include <cstdlib> 
#include <ctime> 

class Ball { 
public: 
    Ball() { std::cout << __func__ << std::endl; } 
    Ball(Ball& other) { std::cout << __func__ << " copy from " << other.getName() << std::endl; } 
    virtual ~Ball() { std::cout << __func__ << std::endl; } 
    virtual std::string getName() = 0; 
    virtual Ball* clone() = 0; 
}; 

class SmallBall : public Ball { 
public: 
    std::string getName() { return "smallBall"; } 
    Ball* clone() { return new SmallBall(*this); } 
}; 

class MediumBall : public Ball { 
public: 
    std::string getName() { return "mediumBall"; } 
    Ball* clone() { return new MediumBall(*this); } 
}; 

class LargeBall : public Ball { 
public: 
    std::string getName() { return "largeBall"; } 
    Ball* clone() { return new LargeBall(*this); } 
}; 

class RandomBallFactory { 
private: 
    std::vector<std::shared_ptr<Ball> > prototypes; 

public: 
    void registerBall(std::shared_ptr<Ball> ball_ptr) { 
     prototypes.push_back(ball_ptr); 
    } 

    std::shared_ptr<Ball> createBall() { 
     int randomNumber = std::rand() % prototypes.size(); 
     return std::shared_ptr<Ball>(prototypes.at(randomNumber)->clone()); 
    } 
}; 

int main(void) { 
    std::srand(std::time(0)); 
    RandomBallFactory randomBallFactory; 

    std::shared_ptr<Ball> sb_ptr(std::make_shared<SmallBall>()); 
    std::shared_ptr<Ball> mb_ptr(std::make_shared<MediumBall>()); 
    std::shared_ptr<Ball> lb_ptr(std::make_shared<LargeBall>()); 

    randomBallFactory.registerBall(sb_ptr); 
    randomBallFactory.registerBall(mb_ptr); 
    randomBallFactory.registerBall(lb_ptr); 

    std::shared_ptr<Ball> ball_ptr(randomBallFactory.createBall()); 
    std::cout << "random Ball is: " << ball_ptr->getName() << std::endl; 
} 
+0

Посмотрите, что это на Java, я могу понять, где вы находитесь отсюда. Но я делаю это на C++, и я не уверен, что заменить cloneable и т. Д. –

+0

@hat_to_the_back Вы ищете решение на C++? Ты серьезно? Почему бы вам не сказать этот вопрос? Почему вопрос связан с Java? Почему ваш пример кода не на C++? – sergej

+0

Спасибо за помощь –

-2

Иерархия классов установки для ваших объектов и использование полиморфизма для их печати. Это общий объектно-ориентированный подход.

+0

Я не спускал вниз (но голосовал, чтобы удалить). Это не касается фундаментального вопроса о создании фабрики. –

0

Самым простым решением является использование switch заявление, что-то вроде:

int randomNumber = ranGen.createRandomNumber(1,3); 
switch (randomNumber) { 
    case 1: 
     // return smallBall 
     break; 
    case 2: 
     // return mediumBall 
     break; 
    case 3: 
     // return largeBall 
     break; 
    default: 
     // handle non-expected value 
     break; 
} 
+2

Хотя замена оператора 'switch' на N случаев для блоков' '' '' '' '' '' '' '' '' 'if' 'if отвечает на заданный вопрос, он не рассматривает основные проблемы масштабируемости и ремонтопригодности, о которых упоминает OP. –

+1

Да, это правильно. Что делать, если у меня было 20 разных объектов одного типа? –

+0

@hat_to_the_back Тогда это зависит от того, какой фактический вариант использования. У разных объектов есть другой набор свойств (например, что вы можете передать конструктору)? И т. Д. –

2

Вы можете использовать Map, что-то вроде этого (при условии, что SmallBall и другие подклассы Ball):

Map<Integer, Ball> balls = new HashMap<Integer, Ball>(); 

balls.put(1, new SmallBall()); 
balls.put(2, new MediumBall()); 
balls.put(3, new LargeBall()); 

RandomGenerator ranGen = new RandomGenerator(); 
Integer randomNumber = ranGen.createRandomNumber(1, balls.size()); 

return balls.get(randomNumber); 

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

Если вы хотите использовать несколько уникальных экземпляры, поставить конкретную шариковую заводы в карту:

Map<Integer, BallFactory> ballFactories = new HashMap<Integer, BallFactory>(); 

ballFactories.put(1, new SmallBallFactory()); 
ballFactories.put(2, new MediumBallFactory()); 
ballFactories.put(3, new LargeBallFactory()); 

RandomGenerator ranGen = new RandomGenerator(); 
Integer randomNumber = ranGen.createRandomNumber(1, balls.size()); 

return ballFactories.get(randomNumber).createBall(); 
1

У вас есть по крайней мере два возможные методы доступны вам для обеспечения генерации случайных объектов без жесткого кодирования неподвижного набор альтернатив:

  1. рандомизация параметров конструктора/завод-метода и
  2. Использование случайным образом выбранного объекта строителя из коллекции таких объектов, поддерживаемых на заводе-изготовителе.

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

interface Builder<T> { 
    T createObject(); 
} 

class Factory<T> { 
    private final List<Builder<? extends T>> builders = new ArrayList<>(); 
    private final RandomGenerator ranGen = new RandomGenerator(); 

    T createRandomObject() { 
     int randomNumber = ranGen.createRandomNumber(0, builders.size() - 1); 

     return builders.get(randomNumber).createObject(); 
    } 

    // Not shown: mechanisms for managing the available Builder objects 
} 
Смежные вопросы