質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

6回答

1953閲覧

【Swift】以下のイケていないコードをリファクタリングするならどうしますか?

pamipani

総合スコア11

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2018/10/05 04:34

編集2018/10/05 05:46

以下のコードをイケてるまで行かなくてもマシなレベルで書くとしたら良い書き方はありますか?

知りたい点

Swiftのswitch文でもうちょいよい書く方法を知りたい。
Swiftならではのswitchの使い方など。
以下のコードだと return 0 や return 1 などDRYではないことが気にはなっています。

補足点

説明は便宜上わかりやすく書き直していて実際の実装はenumなどもう少しマシには書いてある状態。
といった感じです。

雑に質問投げて申し訳ないです。

Swift

1func testMethod(number: Int, tags: [String], products: [String]) -> Int { 2 if tags.isEmpty { 3 switch number { 4 case 0: 5 return 1 6 case 1...tags.count: 7 return 5 8 default: 9 return 0 10 } 11 } else { 12 switch number { 13 case 0: 14 return 1 15 case 1...tags.count: 16 if products.isEmpty { return 0 } 17 return 1 18 case 11...20: 19 return 5 20 default: 21 return 0 22 } 23 } 24} 25

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fuzzball

2018/10/05 04:36

どこらへんが「イケてない」と思っているのか書いて下さい。
pamipani

2018/10/05 04:43

例えば `case 0: return 1 ` や `default: return 0` など処理が重複していてDRYではない点。なんか頑張ればもう少し短くかけるかなと思ってやってみたものの思いつかなかったなど。
fuzzball

2018/10/05 04:52

バグも含めてリファクタリングしないといけないのでしょうか?
fuzzball

2018/10/05 05:03 編集

例えば testMethod(number: 1, tags: [], products: []) で落ちますが、そういうのも残したままでリファクタリングしないといけないのでしょうか?
MasakiHori

2018/10/05 05:20

自分でそれをする時は絶対に必要というわけではないですが、他者にリファクタリングを依頼する場合はユニットテストが絶対に必要です。 まずはユニットテストを書いてください。 もしくはユニットテストが作成可能な仕様書を書いてください。
MasakiHori

2018/10/05 06:39

ユニットテストのない書き換えをリファクタリングと呼んではだめですよ それはただの書き換えです 偉い人に怒られます
guest

回答6

0

ベストアンサーもう出ちゃってて完全に出遅れちゃってる上に、もうみんな色々回答書いてて重箱の隅を突くような真似しかできないけども。switch文ってそれなりの行数取るからswitch文を丸々関数にするのも手ですよね。それだけで割と見通しが良くなる。
あとできるだけtagは使わないようにするとか。tagって増えれば増えるほど管理がめんどくさいですし。

Swiftならではのswitch文と言えばenumとの絡め手かなぁ。上記コードだと前後関係分からないからenumの書き方もなんとも言えないのだけども。ちょいちょい使うのはいくつかある状態をenumで定義しておいてそのenumに対してswitch文を書くとか。
ラストに思いついたのは上記の例だと行数少ないからやらないけど、switch文中の各caseは全部関数にしちゃうとかもよくやります。

投稿2018/10/05 16:55

xAxis

総合スコア1349

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

あくまでも、提示されたコードを見ただけで書き直すとしたら、early returnを優先的に意識して書きます。
ただ、他の方もおっしゃているように、仕様や要件によっていくらでも書き方は変わります。

swift

1func testMethod(number: Int, tags: [String], products: [String]) -> Int { 2 if number == 0 { 3 return 1 4 } 5 6 if tags.isEmpty { 7 return 0 8 } 9 10 if number <= tags.count { 11 if products.isEmpty { 12 return 0 13 } 14 15 return 1 16 } 17 18 if number >= 11 && number <= 20 { 19 return 5 20 } 21 22 return 0 23}

もとのコードでは、特に、caseが以下のようになっているのが嫌な感じがしました。
「例えば、tags.countが15の時は、上を通るんだよね?」っていう確認をしたくなるからです。

swift

1case 1...tags.count: 2case 11...20:

投稿2018/10/05 05:36

編集2018/10/05 05:42
mesoshi

総合スコア56

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pamipani

2018/10/05 06:07

なるほど、雑な質問に答えてもらってありがとうございます! ``` if tags.isEmpty { return 0 } ``` ここ 0返してしまうと説明例の処理と異なりそうな気がするのですが。 tagsがEmptyでもnumberの値によって返す値も変わってくるのです。
pamipani

2018/10/05 06:34

こんな雑な質問に付き合っていただきありがとうございます!early returnを心がけます!
guest

0

リファクタリングの前にデバッグすることをお勧めします。

【追記】

switch文の中の重複を気にしているようですが、tags.isEmptyであればtags.count == 0なので、

swift

1if tags.isEmpty { 2 return number == 0 ? 1 : 0; 3} else { 4 : 5}

で済むと思います。
case 1...tags.count:を通ると落ちるので、ここには絶対来ないものと仮定しています)

投稿2018/10/05 04:44

編集2018/10/05 05:23
fuzzball

総合スコア16731

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pamipani

2018/10/05 05:36

良さそうなヒントが!なるほど。
fuzzball

2018/10/05 05:51 編集

>>以下のコードだと return 0 や return 1 などDRYではないことが気にはなっています。 switchから出せばいいです。 mesoshiさんの回答のように。
guest

0

いろいろなパターンを見たいということならば????のはどうでしょう。
可読性も悪く、自分では使いませんが、、、(※落ちる部分は削除しました)

swift

1func testMethod(number: Int, tags: [String], products: [String]) -> Int { 2 switch (number, tags.count) { 3 case (0, _): return 1 4 case (_, 0): return 0 5 case (1...tags.count, _): return products.isEmpty ? 0 : 1 6 case (11...20, _): return 5 7 default: return 0 8 } 9}

動きを確認したコード

swift

1func testMethod(number: Int, tags: [String], products: [String]) -> Int { 2 if tags.isEmpty { 3 switch number { 4 case 0: 5 return 1 6// case 1...tags.count: 7// return 5 8 default: 9 return 0 10 } 11 } else { 12 switch number { 13 case 0: 14 return 1 15 case 1...tags.count: 16 if products.isEmpty { return 0 } 17 return 1 18 case 11...20: 19 return 5 20 default: 21 return 0 22 } 23 } 24} 25 26 27 28func testMethod1(number: Int, tags: [String], products: [String]) -> Int { 29 switch (number, tags.count) { 30 case (0, _): return 1 31 case (_, 0): return 0 32 case (1...tags.count, _): return products.isEmpty ? 0 : 1 33 case (11...20, _): return 5 34 default: return 0 35 } 36} 37 38print(testMethod(number: 0, tags: [], products: [])) 39print(testMethod1(number: 0, tags: [], products: [])) 40print("---------") 41 42print(testMethod(number: 1, tags: [], products: [])) 43print(testMethod1(number: 1, tags: [], products: [])) 44print("---------") 45 46print(testMethod(number: 1, tags: ["a"], products: [])) 47print(testMethod1(number: 1, tags: ["a"], products: [])) 48print("---------") 49 50print(testMethod(number: 1, tags: ["a"], products: ["a"])) 51print(testMethod1(number: 1, tags: ["a"], products: ["a"])) 52print("---------") 53 54print(testMethod(number: 11, tags: ["a", "b"], products: ["a"])) 55print(testMethod1(number: 11, tags: ["a", "b"], products: ["a"])) 56print("---------") 57 58print(testMethod(number: 21, tags: ["a", "b"], products: ["a"])) 59print(testMethod1(number: 21, tags: ["a", "b"], products: ["a"])) 60print("---------") 61 62

投稿2018/10/05 13:40

_Kentarou

総合スコア8490

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

そのコードがイケてるかイケてないか、って判断は、コード断片だけでなく
全体や要件、開発チームの事情なども合わせて考えないと分からないと考えます。
(請負開発屋の意見です)

それはさておき、いくつか。

tagsが空かどうかというのは、最初に切り分けるべき条件とは思えない。
それが必要なときに改めて切り分ければよいのでは?

numberの値がenumに出来るような有限集合ではなく、あくまで数値範囲であれば、
switchよりif/else ifの方が柔軟性が高い気がする。

投稿2018/10/05 05:20

daisuke7

総合スコア1563

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pamipani

2018/10/05 05:31

なるほど 普通に if/else if か。 ちょっと書いてみまっす。
guest

0

リファクタリングする際に参考にできる考え方はデザインパターンです。
Martin Fowlerさん本
とかDustin Boswellさん , Trevor Foucherさん本
とか結城センセの本
が個人的にオススメです。
switchで多くの場合をケース分けする際にもStateパターンとかがあるので、満足できるのではないでしょうか。

投稿2018/10/05 05:03

t_obara

総合スコア5488

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pamipani

2018/10/05 05:17 編集

リーダブルコードはさすが読んだことある 一番上のリファクタリングは知らなかったので今購入した ありがとう。 ただ自分が今知りたいのは Swiftのswitch文でもうちょいよい書く方法を知りたい。 説明は便宜上わかりやすく書き直していて実際はenum(state)などもう少しマシには書いてある状態。 といった感じです。
t_obara

2018/10/05 05:28

書籍にも記載がありますが、まずどのような前提でのコードなのかを提示した上で、そのような課題を持ったコードに対してどのようにリファクタリングすべきか具体的な事例を交えて示唆を与えるものです。 簡易コードを提示していただいたとしても、背景情報がないと、他の方々からもコメントがある通り、あまり満足のいく回答は得られないのではないでしょうか。 表面的な回答で言えば、先に記載した通り、まずStateパターンの適用をトライして見ては?となります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問