LoginSignup
3
0

More than 3 years have passed since last update.

【Swift】自動販売機の機能を実装してみた

Last updated at Posted at 2020-12-31

私ごとなのですが、メンターのヤマタクさんと契約しておりまして
その中で応用学習としてビジネスロジックを組んでみようという課題がありました。

その中の一つの題材として、
自動販売機のロジックがあったのでそちらを作成してみようと思います!

やる気のある方は、プログラミングスクールよりメンターと契約した方が
安いですし効率もいい気がするので是非お勧めします!

「Swift メンター」で検索!

ロジック作成の前に

以前までの私でしたら何も考えずにコードを組んでいましたが、
順にやることを教えていただいたのでその通りに定義していきたいと思います!

また、先日GitHubについても学習したので
そちらの練習もかねて進めていきたいと思います。

GitHubには次の順序で連携?しました。備忘録として残しておきます。

1.GitHubでリポジトリを作成
2.XCodeでプロジェクトを作成
※作成する時にCreate local git repository for this projectにチェック
3.ターミナルでgit remote add origin リポジトリのURL(https://~)実行
4.XCodeのSource ControllからCommitPushを行う

この順序でできた気がします。

もしできなかったら 3. の後に一度ターミナルから、
git push -u origin mainを実行すれば登録かなんかされてできる様になるかも?

今回のプロジェクトのGitHubリポジトリはコチラになります。

仕様

まずはこの自動販売機のロジックの仕様を考えます。
・初期の所持金を1000円する
・投入可能金額は、10円・50円・100円・500円・1000円とする
・対象の商品は、「いろはす」・「緑茶」・「午後の紅茶」の3種類とする
・商品の詳細は下記のとおり

いろはす 緑茶 午後の紅茶
金額 100円 120円 150円
在庫 3個 2個 1個

・購入は現金のみとする
・商品購入後は、金額表記を減らす。
・おつりボタンを押すと返金される

とりあえずこんな感じの仕様でいきたいと思います!

ちなみに、PlaygroundとStoryboardのどちらでも可なので、
今回はStoryboardで実装したいと思います。

実装していく

まずはUIを適当でいいので実装してみます。
今回は本物の自販機のかなりの劣化版となります・・・(笑)

スクリーンショット 2020-12-30 13.36.26.png

とりあえずこんな感じでどうでしょう!

「購入」・「10円〜1000円」・「おつり」は、UIButton( )で実装しています。
それ以外は、UILabel( )での実装になります。

次に、Storyboardとコードを連携していきます。

各ボタンを別にしてコードにすると量が多くなるなるので、
関連性のあるボタンはまとめてみました。

スクリーンショット 2020-12-30 13.46.41.png

では、一度GitHubにコミットして
バックアップを作成してから実際のコードを記述していきたいと思います。

git resetコマンドがあった気がするので、もし戻したくなったらこれで戻せるはずです。
(こういう使い方が推奨されているのかは分かりませんが・・・。)

では、ここからは処理を書いていきたいと思います。

実装の順としては、実際に購入する際の順で実装していきたいと思います。

最初にお金を入れると思うので、
各金額が記載されているボタンを押したら所持金が減り、
投入金額が増える様なコードを書きたいと思います。

今回は、各金額ボタンが一つのsendMoney()メソッドにまとめられています。
なので、どのボタンが押されたかチェックしてから適した処理を行います。

まず、Storyboardの対象のボタンを選択し、tagに値を設定します。
今回は10円から順にtag1、tag2、tag3、tag4、tag5と振っていきました。

スクリーンショット 2020-12-30 14.08.15.png

その後、switch文でどのタグが選択されたかで条件分岐しています。

引数senderに値が入ってくる訳ですが、
Any型なのでguard-letの箇所でUIButton型にキャストしています。

ViewController.swift
    // 投入額選択ボタン
    @IBAction func sendMoney(_ sender: Any) {
        guard let button = sender as? UIButton else {
            return
        }

        switch button.tag {
        case 1:
            print("1")
        case 2:
            print("2")
        case 3:
            print("3")
        case 4:
            print("4")
        case 5:
            print("5")
        default: return
        }
    }

この時点でどのボタンが押されたかまでは識別できる様になったので、
金額の反映を行うメソッドを定義していきたいと思います。

これから定義するメソッドが実装する機能は、
所持金から投入金額分を引く機能と、金額の値を増やす機能です。

新たにプロパティを二つ定義し、そこの値を更新するメソッドを定義しました。

sendMoneyAction()メソッドでは、押されたボタンの値を引数として受け取り、
所持金からその値を引くのと金額に投入額を追加するのと、各ラベルの更新を行っています。

ViewController.swift

    var money = 1000
    var inputMoney = 0

    // 投入額選択ボタン
    @IBAction func sendMoney(_ sender: Any) {
        guard let button = sender as? UIButton else {
            return
        }

        switch button.tag {
        case 1:
            sendMoneyAction(value: 10)
        case 2:
            sendMoneyAction(value: 50)
        case 3:
            sendMoneyAction(value: 100)
        case 4:
            sendMoneyAction(value: 500)
        case 5:
            sendMoneyAction(value: 1000)
        default: return
        }
    }

    func sendMoneyAction(value: Int) {
        money -= value
        inputMoney += value

        moneyLabel.text = "所持金:\(money)円"
        inputMoneyLabel.text = "金額:\(inputMoney)円"
    }

実際に50円のボタンと100円のボタンを押すと
所持金が850円になり、金額が150円になっているのが分かります。

スクリーンショット 2020-12-30 14.31.41.png

機能を一つ実装したので一度GitHubにコミットし、
次は、お金を入れたら飲み物を買うと思うので、購入ボタンの実装を行います。

こちらも、先ほどと同じくタグで識別します。
似たコードになるので説明は省略します!

左の購入ボタンを押した時は金額から100円を引く。
というコードにしようと思ったのですが、実際は商品の並び替えを行うと思うので
左の購入ボタンがずっと100円とは限りません。

なので、各購入ボタンを押した時に、
商品名を指定してその商品名に適した処理を行うことにしました。

そうすることにより金額の変動や商品位置の変更に対してのメンテナンスが
ほんの少しですが楽になる?と思います。

そうするために、まず列挙型を定義し各商品のケースを定義しました。

購入ボタンを押すと購入処理を行うbuyDrink()メソッドが実行されます。

引数には列挙型Drinkのケースを指定しています。
switch文でパターンマッチを行いそのケースに適した処理を行っています。

ViewController.swift

enum Drink {
    case irohasu
    case ryokucha
    case gogothi
}

    // 購入ボタン
    @IBAction func buyButton(_ sender: Any) {
        guard let button = sender as? UIButton else {
            return
        }

        switch button.tag {
        case 1:
            buyDrink(product: .irohasu)
        case 2:
            buyDrink(product: .ryokucha)
        case 3:
            buyDrink(product: .gogothi)
        default:
            return
        }
    }

    // 購入処理
    func buyDrink(product: Drink) {
        switch product {
        case .irohasu:
            inputMoney -= 100
            inputMoneyLabel.text = "金額:\(inputMoney)円"
            print("いろはすを購入しました。")
        case .ryokucha:
            inputMoney -= 120
            inputMoneyLabel.text = "金額:\(inputMoney)円"
            print("緑茶を購入しました。")
        case .gogothi:
            inputMoney -= 150
            inputMoneyLabel.text = "金額:\(inputMoney)円"
            print("午後ティーを購入しました。")
        }
    }

実際に500円投入後に、午後ティーと緑茶を購入した場合の結果が下記になります。
金額が減り、ログに購入結果が出力されているのが分かります。

スクリーンショット 2020-12-30 15.04.33.png

結構それっぽくなってきましたね!
最後に、投入金額が残った場合におつりボタンを押すと返金される機能を実装します。

と思いましたが、その前にGitHubにコミットします。
開発がどんどん進むとコミットを忘れてしまいそうになります(笑)

おつりボタンの機能はものすごく簡単で、金額の残りを所持金にプラスするだけです。
それだけだと少し寂しいので、ついでにログに出力する処理も追加しておきます。

ViewController.swift

    // おつりボタン
    @IBAction func changeButton(_ sender: Any) {
        money += inputMoney
        print("\(inputMoney)円のおつりをもらいました")
        inputMoney = 0
        moneyLabel.text = "所持金:\(money)円"
        inputMoneyLabel.text = "金額:\(inputMoney)円"
    }

たったこれだけになります。

500円投入後、150円の午後ティーを購入し、
350円のおつりを貰った際の挙動は画像のようになります。

スクリーンショット 2020-12-30 15.17.06.png

所持金が850円で、ログにもしっかり出力されているので問題ないと思います!

これで最低限の自動販売機ロジックの完成になります。

最低限といったのには意味があり、
このコードには例外の処理を一切記載していません。

例えば、1000円を何回もタップし所持金をマイナスにすることもできますし、
金額が0円のまま商品を購入することもできます。
他にも仕様では在庫が決まっているのに何本も買えてしまったりと穴だらけのコードです。

なので、次回の記事でここらへんもしっかりと実装していきたいと思います。

次回の記事はこちらになります。
-> 【Swift】自動販売機の例外処理を実装してみた

最後までご覧いただきありがとうございました。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0