2015-10-28 42 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

我没有downvote(但没有投票删除)。这并没有解决工厂创建的根本问题。 –

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

虽然有N情况下对于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 
}