工厂内部If语句过多

Too Many If Statements Inside Factory

本文关键字:语句 If 内部 工厂      更新时间:2023-10-16

我目前正在开发一个具有许多不同设计模式的应用程序。它需要遵循良好的实践——基本上没有代码气味。

我使用工厂方法打印出随机类型的对象,但我必须使用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
}

另一种方法是应用原型模式

在下面的示例中,我们有一个名为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;
}

您可以使用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);

注意:在本例中,factory方法将始终返回对的引用在三个实例中的一个实例中,没有创建新对象。

如果你想要多个独特的实例,把混凝土球工厂放在地图上:

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. 构造函数/工厂方法参数的随机化,以及
  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
}

最简单的解决方案是使用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;
}