2015-10-28 43 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 
}