swift for循环_一次Swift的编程教学

前几天在给上小学六年级的小孩进行了一次Swift的编程教学,感觉有点意思,在这里记录一下。

教学环境是iPad上的Swift playgrounds,课程是程序设计2中的一个关卡。这个关卡的要求是控制两个角色来完成捡宝石和踩开关的任务,稍麻烦的是如何设计角色的行走路径。具体关卡如下图所示:

0b78d01cbc7aaf5adf00303ec3b72fff.png

好了,现在开始来编程解决这个问题吧。第一个最简单直接的程序如下:

let expert = Expert()
let character = Character()

expert.turnLeft()
expert.moveForward()
expert.moveForward()
expert.moveForward()
expert.turnRight()
expert.moveForward()
expert.moveForward()
expert.turnLeft()
expert.turnLockDown()
expert.turnLockDown()
expert.turnRight()
expert.moveForward()
expert.moveForward()
expert.trunRight()
expert.moveForward()
expert.moveForward()
expert.moveForward()
expert.moveForward()
expert.moveForward()
expert.moveForward()
expert.turnRight()
expert.moveForward()
expert.moveForward()
expert.turnLeft()
expert.turnLockUp()

character.moveForward()
character.moveForward()
character.collectGem()
character.moveForward()
character.moveForward()
character.toogleSwitch()

上面这个程序很直接,但是有很多重复的moveForward()函数调用,如何消除这些重复的函数调用呢?最直接的解决方法就是使用for循环来代替这些重复的调用,于是我们有了如下的使用了for循环的第二个程序,如下所示:

let expert = Expert()
let character = Character()

expert.turnLeft()
for i in 1..3 {
    expert.moveForward()
}
expert.turnRight()
for i in 1..2 {
    expert.moveForward()
}
expert.turnLeft()
expert.turnLockDown()
expert.turnLockDown()
expert.turnRight()
for i in 1..2 {
    expert.moveForward()
}
expert.turnRight()
for i in 1..6 {
    expert.moveForward()
}
expert.turnRight()
for i in 1..2 {
    expert.moveForward()
}
expert.turnLeft()
expert.turnLockUp()

for i in 1..2 {
    character.moveForward()
}
character.collectGem()
for i in 1..2 {
    character.moveForward()
}
character.toggleSwitch()

这回这些重复的moveForward函数调用都没有了,不过我们仔细看看这些for循环,可以发现除了1..2,1..3,1..6中的2,3,6不同外,其他都是一样的。如果我们将2,3,6使用一个变量distance来代替,那这些for循环就完全一样了。于是我们将for循环放到一个函数中,把distance变量作为这个函数的参数,其值在调用这个函数时设置为2,3,6这几个不同的值就可以了。嗯,看起来不错,于是有了下面的第三个程序:

let expert = Expert()
let character = Character()

func moveExpert(distance: Int)
{
    for i in 1..distance {
        expert.moveForward()
    }
}

func moveCharacter(distance: Int)
{
    for i in 1..distance {
        character.moveForward()
    }
}

expert.turnLeft()
moveExpert(distance: 3)
expert.turnRight()
moveExpert(distance: 2)
expert.turnLeft()
expert.turnLockDown()
expert.turnLockDown()
expert.turnRight()
moveExpert(distance: 2)
expert.turnRight()
moveExpert(distance: 6)
expert.turnRight()
moveExpert(distance: 2)
expert.turnLeft()
expert.turnLockUp()

moveCharacter(distance: 2)
character.collectGem()
moveCharacter(distance: 2)
character.toggleSwitch()

将for循环的行为抽象为函数后,我们的程序的主流程变短了很多,更清晰,意思更明确,也更容易读了。不过还有不足的是这两个move函数moveExpert和moveCharacter的实现几乎是完全一样的,除了expert和character的区别。能否统一两个函数呢,首先想到的是将expert和character也使用一个变量来替代,作为参数传入进来。但expert和characer的类型是不一样的,分别是Expert和Charater,似乎不能使用一个变量来替代。不过注意到Expert是Character的子类型,根据子类型替换原则,我们可以使用Character类型的变量来表示Expert类型的变量。于是我们就可以使用一个变量来替代expert和character了,就可以将函数moveExpert和moveCharacter统一为一个函数move了。代码如下:

func move(sprite: Character, distance: Int)
{
    for i in 1..distance {
        sprite.moveForward()
    }
}

我们再来仔细看看expert角色的行走路径,可以发现是存在一个模式的,即先往前,拐弯,然后再往前。我们可以把这个共性的行为抽象出来,将行走模式抽象为一个函数moveTurnMove,我们就得到了第四个程序。

let expert = Expert()
let character = Character()

func move(sprite: Character, distance: Int)
{
    for i in 1..distance {
        sprite.moveForward()
    }
}

func moveTurnMove(distance1: Int, isTurnLeft: Bool, distance2: Int)
{
    move(sprite: expert, distance: distance1)
    if isTurnLeft {
        expert.turnLeft()
    } else {
        expert.turnRight()
    }

    move(sprite: expert, distance: distance2)
}

expert.turnLeft()
moveTurnMove(distance1: 3, isTurnLeft: false, distance2: 2)
expert.turnLeft()
expert.turnLockDown()
expert.turnLockDown()
expert.turnRight()
moveTurnMove(distance1: 2, isTurnLeft: false, distance2: 3)
moveTurnMove(distance1: 3, isTurnLeft: false, distance2: 2)
expert.turnLeft()
expert.turnLockUp()

move(sprite: character, distance: 2)
character.collectGem()
move(sprite: character, distance: 2)
character.toggleSwitch()

最终,我们得到了一个主流程更短的程序,更清晰明确了,读起来更容易理解了。当地图更大更复杂,角色的行走路径更多步骤时,我们就可以节约很多代码,而且更不容易出错。良好的抽象层次可以减少大量重复的代码,而且使程序的行为更加清晰明确,不容易出错,使得读代码的人也更轻松了,不会一下子就陷入到细节中去。

这次教学到这里就结束了。通过多次修改通关的程序,我们从一个简单直接,但抽象度低,冗长啰嗦,不好阅读的程序开始,一步一步的提升抽象层次,得到了明确清晰,容易阅读的程序。这也是我们在工作实践中设计复杂程序的一种良好的方法,从一开始让小孩熟悉这种设计程序的方法是很有益处的。

这个程序还有重复的代码没有去除,moveTurnMove函数也还可以写的更通用些。这些就留给有兴趣的读者来思考吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值