返回介绍

1.1 抽象工厂模式

发布于 2025-01-04 00:44:54 字数 3990 浏览 0 评论 0 收藏 0

抽象工厂模式 能将一组有共同主题的独立工厂封装起来。它将普通工厂的意图具体化,例如:不必再利用代码通过使用接口来了解接口背后的具体实施,而应用于一组接口,并且选择一整套能够实现这些接口的具体类。

考虑这样一个范例,其中有接口 Button、TextField 和 Scrollbar。将 WindowsButton、MacButton、FlashButton 作为 Button 的具体类。WindowsScrollBar、MacScrollBar 和 FlashScrollBar 作为 ScrollBar 的具体实现。抽象工厂模式应能让我选择某次想要用到的具体窗口系统(比如 Windows、Mac、Flash),并从此可以编写代码引用这些接口,但能一直在后台使用正确的具体类(来自某个窗口系统)。

1.1.1 范例

假设我们要写一个游戏系统,可能会注意到很多游戏其实都有非常一致的功能与控制方式。

于是我们打算把通用和游戏专有的代码分别写到不同的类中。

首先来看看游戏 Two-Up (一种投掷双币赌博的游戏)专有代码 :

class TwoupMessages {
  def welcome = 'Welcome to the twoup game, you start with $1000'
  def done = 'Sorry, you have no money left, goodbye'
}

class TwoupInputConverter {
  def convert(input) { input.toInteger() }
}

class TwoupControl {
  private money = 1000
  private random = new Random()
  private tossWasHead() {
    def next = random.nextInt()
    return next % 2 == 0
  }
  def moreTurns() {
    if (money > 0) {
      println "You have $money, how much would you like to bet?"
      return true
    }

    false
  }
  def play(amount) {
    def coin1 = tossWasHead()
    def coin2 = tossWasHead()
    if (coin1 && coin2) {
      money += amount
      println 'You win'
    } else if (!coin1 && !coin2) {
      money -= amount
      println 'You lose'
    } else {
      println 'Draw'
    }
  }
}

下面再来看看猜数字游戏的游戏专有代码:

class GuessGameMessages {
  def welcome = 'Welcome to the guessing game, my secret number is between 1 and 100'
  def done = 'Correct'
}

class GuessGameInputConverter {
  def convert(input) { input.toInteger() }
}

class GuessGameControl {
  private lower = 1
  private upper = 100
  private guess = new Random().nextInt(upper - lower) + lower
  def moreTurns() {
    def done = (lower == guess || upper == guess)
    if (!done) {
      println "Enter a number between $lower and $upper"
    }

    !done
  }
  def play(nextGuess) {
    if (nextGuess <= guess) {
      lower = [lower, nextGuess].max()
    }
    if (nextGuess >= guess) {
      upper = [upper, nextGuess].min()
    }
  }
}

下面再来写工厂代码:

def guessFactory = [messages: GuessGameMessages, control: GuessGameControl, converter: GuessGameInputConverter]
def twoupFactory = [messages: TwoupMessages, control: TwoupControl, converter: TwoupInputConverter]

class GameFactory {
  def static factory
  def static getMessages() { return factory.messages.newInstance() }
  def static getControl() { return factory.control.newInstance() }
  def static getConverter() { return factory.converter.newInstance() }
}

工厂的重点在于允许选择整组具体类。

下面是对工厂的使用:

GameFactory.factory = twoupFactory
def messages = GameFactory.messages
def control = GameFactory.control
def converter = GameFactory.converter
println messages.welcome
def reader = new BufferedReader(new InputStreamReader(System.in))
while (control.moreTurns()) {
  def input = reader.readLine().trim()
  control.play(converter.convert(input))
}
println messages.done

第一行配置了所要使用哪一组具体游戏类。其实,通过像第一行中那样使用 factory 属性来确定所用类组并不是很重要。通过其他方式也可以实现这一点。比如,我们可以询问用户想玩的游戏,或者从环境设置中确定使用何种游戏。

根据以上的代码,游戏运行结果大概如下所示:

Welcome to the twoup game, you start with $1000
You have 1000, how much would you like to bet?
300
Draw
You have 1000, how much would you like to bet?
700
You win
You have 1700, how much would you like to bet?
1700
You lose
Sorry, you have no money left, goodbye

如果把第一行脚本改为: GameFactory.factory = guessFactory ,那么范例运行结果如下:

Welcome to the guessing game, my secret number is between 1 and 100
Enter a number between 1 and 100
75
Enter a number between 1 and 75
35
Enter a number between 1 and 35
15
Enter a number between 1 and 15
5
Enter a number between 5 and 15
10
Correct

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文