轨道
/
Crystal
Crystal
/
练习
/
贝尔布鲁克篮球联赛
贝尔布鲁克篮球联赛

贝尔布鲁克篮球联赛

学习练习

简介

Crystal 中的模块有两个用途:

第一个用途是创建命名空间,以避免名称冲突。 不过,它也会把代码组织起来,让人更容易看懂代码的用途。

第二个用途是定义混入,把代码共享给各个类型。

模块和类很相似,但主要区别在于:模块不能被实例化,因此也没有实例变量。

要声明一个模块,使用module关键字,后面跟上模块的名字。

module Foo
end

命名空间

命名空间是一种组织代码的方式。 这样可以避免名称冲突,也更容易看清代码的用途。 如果想访问放在某个命名空间里的常量或类,就要使用::运算符。

module Foo
  class Bar
  end
end

Foo::Bar.new

把模块用作混入

例如,当多个类需要相同的“基础”功能,或者需要在互不相关的类之间共享代码时,这就会很有用。 或者,当你想在不相关的类之间共享代码时,也可以这么做。

把模块用作混入有两种方式:第一种是使用include关键字,第二种是使用extend关键字。

两种方式都会让模块中的常量对包含或扩展该模块的类型可用。

包含

包含会让模块中的所有方法都变成包含该模块的类型的实例方法。 include关键字应写在类型的顶部,后面跟上模块的名字。

module Foo
  def foo
    "foo"
  end
end

class Bar
  include Foo
end

Bar.new.foo # => "foo"

扩展

扩展的用法和包含类似,但它不会把方法变成实例方法,而是把它们变成类方法。 extend关键字应写在类型的顶部,后面跟上模块的名字。

module Foo
  def foo
    "foo"
  end
end

class Bar
  extend Foo
end

Bar.foo # => "foo"

extend self

Crystal 中一种常见的模式,是在模块里使用 extend self 模式。 这样,模块中的所有方法都会变成模块自身的类方法。 这意味着你不需要用def self.method_name语法把每个方法都挂到模块上。

module Foo
  extend self

  def foo
    "foo"
  end
end

Foo.foo # => "foo"

说明

Bellebrook 篮球联盟是一个由多支球队组成的联盟,每支球队都有一份球员名单。新赛季即将开始,他们需要创建一套新的票务系统来售卖比赛门票。上个赛季,他们在球馆入口处售票,但人气暴涨,于是他们决定本赛季改为在线售票,以应对增长的需求。

联盟联系了你,请你创建一个处理门票销售的系统。

1. 创建票务系统

首先,你需要创建一套票务系统来处理门票销售。票务系统需要说明一场比赛有多少张票可售。

每场比赛都应该创建一个名为 TicketSystem 的类的实例。初始化后的状态应包含以下信息:

  1. 这场比赛有多少张可售门票。
  2. 比赛在哪个球馆举行。

通过实参构造初始化状态,这些实参分别表示可售门票的数量和比赛所在的球馆。初始化状态应包含实例变量 @tickets_available 和 @stadium。它们分别保存传入的第一个和第二个实参。

TicketSystem.new(100, "Bellebrook")
# => #<TicketSystem:0x10f0b8 @tickets_available=100, @stadium="Bellebrook">

2. 获取可售门票的数量

首先,你需要创建一个方法,返回某场比赛的可售门票数量。

在已经定义好的类上方定义一个名为 TicketingReservation 的模块。这个模块应该被 TicketSystem 类包含。

在模块内部,定义一个名为 tickets_available 的方法。这个方法应该返回可售门票的数量。

ticket_system = TicketSystem.new(100)
ticket_system.tickets_available
#=> 100

3. 订购门票

你需要创建一个方法,检查某场比赛是否还有门票可售。每场比赛需要预留 100 张票。这是为了确保在球馆入口处买票的人始终能买到票。

在 TicketingReservation 模块内部,定义一个名为 order_ticket? 的方法。如果有至少 100 张票可售,该方法应返回 true,否则返回 false。如果有至少 100 张票可售,该方法还应把可售门票的数量减少 1。

ticket_system = TicketSystem.new(100)
ticket_system.order_ticket?
#=> true

4. 订购提示信息

票务系统的提示信息必须让用户容易理解。而且这些信息应该显得个性化,所以要包含用户的名字。

如果购票成功,用户应该收到一条消息,告诉他们购票成功、他们的票号,以及比赛在哪个球馆举行。票号应该是下单前可售门票的数量。

如果购票成功,消息应该像这样:{name}, your purchase was successful, your ticket number is #{ticket_number}, and the game is played at the {stadium_name} stadium.。 如果购票失败,消息应该像这样:{name}, your purchase was unsuccessful, there are not enough tickets available.。

在 TicketingReservation, 模块内部,定义一个名为 order_message 的方法,该方法接收一个实参 name,其中包含购票者的名字。该方法应返回一个包含这条信息的字符串。

ticket_system = TicketSystem.new(100, "Bellebrook")
ticket_system.order_message("John")
#=> "John, your purchase was successful, your ticket number is #100, and the game is played at the Bellebrook stadium."
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Crystal Exercism

准备好开始 贝尔布鲁克篮球联赛 了吗?

注册 Exercism,借助 26 个概念142 个练习 和真人导师指导,学习并掌握 Crystal,全部免费。