2012-11-30 17 views
20

一般的なスタイルの質問。Scalaオブジェクトとシングルトンの台頭

私は機能コードを書くのが良くなったので、私のメソッドの多くは純粋な機能になっています。私は多くの "クラス"(コードのコンテナの緩やかな意味で)が無償状態になっていることがわかりました。したがって、私はそれらをインスタンス化する必要がないので、クラスではなくオブジェクトにします。

"静的"メソッドでいっぱいのクラスを持つことはかなり奇妙に思えますが、一般的にはGuavaやCommons- *などのように "ヘルパー"クラスでのみ使用されます。

私の質問は、Scalaの世界では、 "オブジェクト"の内部にはかなりの論理があり、 "クラス"はそれほど正常ではない、あるいは別の優先イディオムがあります。

+0

状態が無ければ、なぜオブジェクトであり、単に関数ではないのですか? – RonaldBarzell

+3

あなたは何かの中に関数を置く必要はありません、これは私の質問です。私は関連する機能をたくさん持っています。オブジェクトの内部にあり、単にコンテナとして機能します。これはScalaでベストプラクティスとみなされるかどうかです。 – monkjack

+0

よろしいですか?私は誤解しました。説明をありがとうございます。 – RonaldBarzell

答えて

16

あなたのタイトルで言及しているように、オブジェクトはシングルトンクラスであり、あなたの質問のテキストで言及する静的メソッドを持つクラスではありません。

そして、Javaの世界では、静的ANDシングルトンよりもスケーラオブジェクトが優れている点がいくつかあります。したがって、スカラで使用するのはかなり「正常」です。

scala> trait Quack {def quack="quack"} 
defined trait Quack 

scala> class Duck extends Quack 
defined class Duck 

scala> object Quacker extends Quack {override def quack="QUAACK"} 
defined module Quacker 

// MakeItQuack expects something implementing Quack 
scala> def MakeItQuack(q: Quack) = q.quack 
MakeItQuack: (q: Quack)java.lang.String 

// ...it can be a class 
scala> MakeItQuack(new Duck) 
res0: java.lang.String = quack 

// ...or it can be an object 
scala> MakeItQuack(Quacker) 
res1: java.lang.String = QUAACK 

これは、密結合せずに、グローバルな状態を促進することなく、それらが使用可能になる(の2である:あなたが簡単に依存関係としてのオブジェクトを注入することができますので、一つには

は、静的メソッドとは異なり、オブジェクトのメソッドは、多形性あり一般に静的メソッドとシングルトンの両方に起因する問題)。

次に、シングルトンをJavaで見ているようにシングルトンを作成するための定型文をすべて削除するという事実があります。これはしばしば見過ごされている点です。私の意見では、シングルトンをステートレスでグローバルな状態として使用していない場合でも、Javaで悩まされている部分の一部です。

また、すべてのJavaシングルトンで繰り返さなければならない定型文では、クラス自体のインスタンスが1つしかなく、実行する必要があることをすべて実行するという2つの責任が与えられます。スカラーが何かがシングルトンであることを指定する宣言的な方法があるという事実は、クラスとプログラマーが単一責任の原則を破棄するのを軽減します。スカラーでは、オブジェクトがシングルトンであることを知っています。そして、あなたはそれが何をするかについてただ理由を知ることができます。

+5

私は、スケーラオブジェクトが何かを拡張できるということを十分に強調することはできないと考えています。これは依存関係注入イディオム。例を与えてくれてありがとう! –

+0

@ChristianSchlichtherleありがとう、私はちょうど私が良い例を持っていたらいいと思う。私は与えた人為的なものがあまり好きではない... –

2

はい、私はそれが正常だと言います。

ほとんどのクラスでは、そこにいくつかの初期化/検証ロジックを処理するためのコンパニオンオブジェクトを作成します。

class X(val x: Int) { 
    require(x >= 0) 
} 
// ==> 
object X { 
    def apply(x: Int): Option[X] = 
    if (x < 0) None else Some(new X(x)) 
} 
class X private (val x: Int) 

コンパニオンオブジェクトには1がの多くを追加することができます。代わりに、パラメータの検証が失敗した場合は、コンストラクタで例外をスローする例については、仲間内OptionまたはEitherが適用法オブジェクトを返すことが可能です不変オブジェクト用のキャッシュなどの追加ロジック。

オブジェクトはまた、メッセージを送信する必要がない場合は、インスタンス間の信号を送信するのに適しています:オブジェクトのための

object X { 
    def doSomething(s: String) = ??? 
} 
case class C(s: String) 

class A extends Actor { 
    var calculateLater: String = "" 
    def receive = { 
    case X => X.doSomething(s) 
    case C(s) => calculateLater = s 
    } 
} 

別のユースケースは、要素の範囲を削減することである。

// traits with lots of members 
trait A 
trait B 
trait C 

trait Trait { 

    def validate(s: String) = { 
    import validator._ 
    // use logic of validator 
    } 

    private object validator extends A with B with C { 
    // all members of A, B and C are visible here 
    } 
} 

class Class extends Trait { 
    // no unnecessary members and name conflicts here 
} 
関連する問題