工厂内部的 If 语句过多
Too Many If Statements Inside Factory
我目前正在开发一个包含许多不同设计模式的应用程序。它需要遵循良好的实践,基本上没有代码味道。
我正在使用工厂方法打印出随机类型的对象,但我必须使用 3 个 if 语句,这似乎效率低下...如果我想打印出 10 个不同的对象会怎样?难道只需要添加更多 if 语句就没有其他解决方法吗?
** 这种特殊方法在工厂中的最终用途是 return 球类型的随机对象 (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
}
最简单的解决方案是使用 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;
}
你可以使用 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);
注意:在这个例子中,工厂方法总是return引用
三个实例之一,没有创建新对象。
如果你想要多个独特的实例,请将具体的 Ball-factories 放入地图中:
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();
您至少有两种可能的技术可用于提供随机生成对象,而无需对一组固定的备选方案进行硬编码:
- 构造函数/工厂方法参数的随机化,以及
- 使用从工厂维护的此类对象集合中随机选择的构建器对象。
我将重点关注后者。 return 来自预先构建的集合中的随机元素的建议是一种特殊情况,其中构建器对象平凡地将自己提供为生成的对象。更一般的形式可能类似于:
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
}
另一种方法是应用 prototype pattern.
在下面的例子中,我们有一个名为 RandomBallFactory
的 class
通过克隆已注册的原型创建随机(唯一)Ball
个实例。
优点:
- 我们可以添加新的
Ball
子 class,而无需更改 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;
}
我目前正在开发一个包含许多不同设计模式的应用程序。它需要遵循良好的实践,基本上没有代码味道。
我正在使用工厂方法打印出随机类型的对象,但我必须使用 3 个 if 语句,这似乎效率低下...如果我想打印出 10 个不同的对象会怎样?难道只需要添加更多 if 语句就没有其他解决方法吗?
** 这种特殊方法在工厂中的最终用途是 return 球类型的随机对象 (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
}
最简单的解决方案是使用 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;
}
你可以使用 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);
注意:在这个例子中,工厂方法总是return引用 三个实例之一,没有创建新对象。
如果你想要多个独特的实例,请将具体的 Ball-factories 放入地图中:
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();
您至少有两种可能的技术可用于提供随机生成对象,而无需对一组固定的备选方案进行硬编码:
- 构造函数/工厂方法参数的随机化,以及
- 使用从工厂维护的此类对象集合中随机选择的构建器对象。
我将重点关注后者。 return 来自预先构建的集合中的随机元素的建议是一种特殊情况,其中构建器对象平凡地将自己提供为生成的对象。更一般的形式可能类似于:
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
}
另一种方法是应用 prototype pattern.
在下面的例子中,我们有一个名为 RandomBallFactory
的 class
通过克隆已注册的原型创建随机(唯一)Ball
个实例。
优点:
- 我们可以添加新的
Ball
子 class,而无需更改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;
}