it-swarm-ja.com

オブジェクトのプロパティを計算する関数を同じクラス内で定義する必要があるのはいつですか?

以下の例として、isClient()関数をAttendeeクラスの一部にする必要がありますか?

import Foundation

///A Node that can be used with the CriteriaEvaluator to determine if clients are present in a Meeting.
class ClientCriteria  : Node {

/**
 Calculates a score from 0..1 to identify the likelihood that a list of Attendees contains a client
 */
func score(attendees : [Attendee]) -> Double
{
    for attendee in attendees
    {
        if isClient(attendee: attendee)
        {
            return 1
        }
    }
    return 0
}

private func isClient(attendee: Attendee) -> Bool
{
    let IBMEmailRegex = "[\\/\\w+\\s*]+\\/IBM\\@?\\w*$"
    if attendee.email.contains(IBMEmailRegex) {
        return false
    }
    else{
        return true
    }
}

}

1
Declan McKenna

isClient()は真の関数です。状態に依存せず、同じ入力が与えられると常に同じ値を返します。

これは、どこでも使用できることを意味します。他の場所で価値がある場合は、スーパークラスまたはユーティリティクラスに移動することを検討してください。ここでしか価値がない場合は、混乱を防ぐためにここに保管してください。他の誰かがそれを利用できる場合は、いつでも後で移動できます。

1つのマイナーな個人的な好み:私は好む

return !attendee.email.contains(IBMEmailRegex) 

あなたがここに持っているものに。私は小さなコードが好きです:)

3
WillD

別の回答で述べたように、特定の関数はオブジェクトの状態にアクセスしません。したがって、どこでも定義できます。

ただし、状態にアクセスする関数はすべて、クラス自体で定義する必要があります。それがカプセル化のすべてです。

2
Frank Puffer

一般的な経験則では、メソッドがselfにアクセスせず、プロトコル/スーパークラスメソッドを実装/オーバーライドするためにそこにない場合、それは間違ったクラスにあります。そこに移動した場合に自分自身にアクセスする別のクラスがある場合は、そのクラスが必要です。この場合、isClientAttendeeに依存しているため、Attendeeにアタッチする必要があります。ただし、プライベート状態に依存しないため、拡張機能に入れる必要があります。

拡張する理由を説明しましょう...最終的に、以下に定義するisClientメソッドは、1つの引数を取るグローバル関数です... _func Attendee.isClient: Bool_とfunc isClient(attendee: Attendee) -> Boolはコールサイトでどのように見えるかです。 他の違いはありません!メソッドを拡張機能に入れることで、この事実がより明確になります。 (それがオブジェクト自体にある場合、それはメソッドが機能するためにクラスのプライベート部分を必要とすることを意味します。)

また、それはO(1)であり、同じ入力が与えられると常に同じ値を返すため、計算されたプロパティとして定義する必要があります。

_extension Attendee {
    var isClient: Bool {
        let IBMEmailRegex = "[\\/\\w+\\s*]+\\/IBM\\@?\\w*$"
        return email.contains(IBMEmailRegex) == false
    }
}
_

scoreも自己に依存していないようです...多分スコアはあなたが言及しなかったプロトコルを実装していますか?そうでない場合は、これもクラスから移動する必要がありますが、実装はO(n)であるため、次の関数である必要があります。

_extension Sequence where Iterator.Element == Attendee {
    /// Calculates a score from 0..1 to identify the likelihood that a list of Attendees contains a client
    func score() -> Double {
        return contains(where: { $0.isClient }) ? 1 : 0
    }
}
_

たぶんClientCriteriaには一連の参加者が含まれていますか?もしそうなら、私はそれをClientCriteriaクラスに残します

_class ClientCriteria : Node {
    private var attendees: [Attendees] = []
    /// Calculates a score from 0..1 to identify the likelihood that a list of Attendees contains a client
    func score() -> Double {
        return attendees.contains(where: { $0.isClient }) ? 1 : 0
    }
}
_

または:

_class ClientCriteria : Node {
    private (set) var attendees: [Attendees] = [] // at least the setter should probably be private.
}

extension ClientCriteria {
    /// Calculates a score from 0..1 to identify the likelihood that a list of Attendees contains a client
    func score() -> Double {
        return attendees.contains(where: { $0.isClient }) ? 1 : 0
    }
}
_
1
Daniel T.

参加者のメソッドにしない理由は、参加者のデータにアクセスしないためではなく、参加者のデータにアクセスするだろうメソッドにする場合メンバー(メールアドレス)。それを比較するためのマスクはかなり恣意的ですが、それは出席者ドメイン外の知識です。それがあなたがそれを含めない理由です。次に、出席者に子供がいるかどうかをチェックするメソッドを追加します。これは、出席とは関係がなく、気が付く前に神のクラスがあることです。

したがって、使用されるデータの範囲を見てください。出席者のものだけを扱う場合は、それをメソッドにします。他の種類の知識が関係している場合は、それを外部に持ち出すか、引数を介して外部データをメソッドに挿入します。

1
Martin Maat