20

一般的なスタイルの質問.

関数型コードの記述が上手になるにつれて、私のメソッドの多くが純粋な関数になりつつあります。多くの「クラス」(コードのコンテナーという大まかな意味で) がステート フリーになっていることがわかりました。したがって、インスタンス化する必要がないため、クラスではなくオブジェクトにします。

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

だから私の質問は、Scala の世界では、「クラス」ではなく「オブジェクト」内に多くのロジックがあること、または別の好ましいイディオムがあることです。

4

3 に答える 3

16

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

そして、scala オブジェクトが java-world の static と singleton の両方よりも優れているいくつかの点があるため、scala でそれらを使用するのは非常に「普通」です。

1 つには、静的メソッドとは異なり、オブジェクト メソッドはポリモーフィックであるため、オブジェクトを依存関係として簡単に注入できます。

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 シングルトンで繰り返さなければならないボイラープレートにより、クラスには 2 つの責任が与えられます。それは、それ自体のインスタンスが 1 つだけであることを保証することと、クラスが行うべきことをすべて実行することです。何かがシングルトンであることを指定する宣言的な方法が scala にあるという事実は、クラスとプログラマーが単一責任の原則を破ることから解放されます。scala では、オブジェクトがシングルトンであることを知っており、それが何をするかについて推論することができます。

于 2012-11-30T15:08:57.927 に答える
4

パッケージ オブジェクトを使用することもできます。たとえば、ここで scala.math パッケージ オブジェクトを見て ください https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_1_final/src//library/scala/math/package .scala

于 2012-11-30T16:11:52.217 に答える
2

はい、それが普通だと思います。

ほとんどのクラスで、コンパニオン オブジェクトを作成して、初期化/検証ロジックを処理します。たとえば、コンストラクターでパラメーターの検証が失敗した場合に例外をスローする代わりに、コンパニオン オブジェクトの apply-method でOptionまたはを返すことができます。Either

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)

コンパニオン オブジェクトでは、不変オブジェクトのキャッシュなど、多くのロジックを追加できます。

メッセージも送信する必要がない場合、オブジェクトはインスタンス間でシグナルを送信するのにも適しています。

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
  }
}

オブジェクトのもう 1 つの使用例は、要素のスコープを縮小することです。

// 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
}
于 2012-11-30T14:29:21.283 に答える