2017-07-04 18 views
1

私は抽象クラスを作成し、それを実装したクラスのコンパニオンオブジェクトの参照属性をメンバーを追加できるようにしたいと思います。このような何か(Scalaの擬似コード):スカラ:抽象クラスのコンパニオンオブジェクトのメンバーを要求することは

abstract class Fruit(cultivar: String) { 
    // How do I reference the implementing class's companion object here? 
    def isTastyCultivar(): Boolean = Fruit.tastyCultivars.contains(cultivar) 
} 

// how do I implement what I am thinking of as "the abstract companion object" 
abstract object Fruit { 
    val tastyCultivars: Set[String] // must be implemented 
            // by the concrete object 
} 

class Apple(cultivar: String) extends Fruit(cultivar) { 

} 

object Apple extends Fruit{ // presumably this is not correct; 
          // it needs to extend the FruitObject 
          // or whatever it is 
    val tastyCultivars: Set[String] = Set("Red Delicious", "Granny Smith") 
} 

class Tomato(cultivar: String) extends Fruit(cultivar) { 

} 

object Tomato extends Fruit{ 
    val tastyCultivars = Set("Roma") 
} 

val a1 = new Apple("Red Delicious") 
val a2 = new Apple("Honeycrisp") 

a1.isTastyCultivar() // should return true 
a2.isTastyCultivar() // should return false 

val t1 = new Tomato("Roma") 
val t2 = new Tomato("San Marzano") 

t1.isTastyCultivar() // should return true 
t2.isTastyCultivar() // should return false 

申し訳ありませんが、これはばかな質問である場合、または(私が簡単に検索できなかったので、私はどのように言葉この質問をするに自信がないんだけど)以前に依頼された場合。前もって感謝します!

+0

あなたの問題は、これらの 'isTastyCultivar'メソッドの作成を強制する方法ですか? –

+0

2つの問題。 isTastyCultivarでは具体的なオブジェクト(Fruit.tastyCultivarsを置き換えるもの)と2つの具体的なオブジェクトをどのように参照するのですか?2つの具体的なオブジェクトでtastyCultivarsの宣言を強制するには –

+0

つまり、特に再定義する必要はありません各具体クラスのisTastyCultivar()メソッド –

答えて

0

単純な解決法(1つのScala Collections use):クラスにコンパニオンを返すメソッドを追加するだけです。

trait FruitCompanion { 
    val tastyCultivars: Set[String] 
} 

abstract class Fruit(cultivar: String) { 
    def companion: FruitCompanion 
    def isTastyCultivar(): Boolean = companion.tastyCultivars.contains(cultivar) 
} 

class Apple(cultivar: String) extends Fruit(cultivar) { 
    def companion = Apple 
} 

object Apple extends FruitCompanion { 
    val tastyCultivars: Set[String] = Set("Red Delicious", "Granny Smith") 
} 

あなたはcompanionが実際にコンパニオンオブジェクトを返しますが、あなたが本当にそれを必要としないことを強制することはできません。

+0

それはまさに私が探していたものです、ありがとう、私はあなたをアップアップしますが、私のアカウントはあまりにも新しく、 –

1

一つの可能​​な解決策は、type class patternを使用することです。私たちは、ADTを経由して、当社のドメインモデル(または代数)を持っている:

sealed trait Fruit 
case class Apple() 
case class Orange() 

我々は提供したい構造を定義し、当社の型クラス、持っている:おいしい品種を持ってい

trait TastyCultivarSupplier[T <: Fruit] { 
    def tastyCultivars: Set[String] 
} 

をそして今、それぞれのタイプになりますそれらを提供するために型クラスを実装する必要があります。

:、我々は TastyCultivarSupplierの暗黙の証拠を必要とし、消費者インサイド

object Apple { 
    implicit def appleTastyCultivars = new TastyCultivarSupplier[Apple] { 
    override def tastyCultivars: Set[String] = Set("Yummy stuff") 
    } 
} 

、またはおいしい品種を取得したいタイプ:これを行うための1つの可能な方法は、コンパニオンオブジェクト内の型クラスを実装することです

class TastyCultivarConsumer { 
    def isTasty[T: TastyCultivarSupplier](name: String): Boolean = 
    implicitly[TastyCultivarSupplier[T]].tastyCultivars.contains(name) 
} 

isTastyが呼び出されると、それはそれ以外の場合は、コンパイル時にエラーが発生します、スコープのサプライヤーの一つを持っている必要があります:

def main(args: Array[String]): Unit = { 
    println(new TastyCultivarConsumer().isTasty("Yummy stuff")) 
} 

私たちを与える:

def main(args: Array[String]): Unit = { 
    import Apple._ 
    println(new TastyCultivarConsumer().isTasty("Yummy stuff")) 
} 

そして、今、私たちのコードがコンパイルされます。

Error:(33, 48) could not find implicit value for evidence parameter 
of type TastyCultivarSupplier[T] 
    println(new TastyCultivarConsumer().isTasty("Yummy stuff")) 

はこれを修正するために、我々は、私たちが望むサプライヤーをインポートします。実装者は、コンパニオンオブジェクト内にエビデンスを書き込むことを余儀なくされるのではなく、コンパイラが見つけることができる範囲内であればどこでも自由に行うことができます。

+0

詳細な回答はありがとうございます。しかし、AppleクラスをTastyCultivarConsumer()にする方法はまだ分かりません。つまり、メインで終わりたいのは、代わりに println(新しいApple( "Yummy stuff").isTasty()) –

0

あなたが求めているものを行うことはできません。

あなたはobjectのメンバーを上書きについて尋ねています。 scalaのobjectは、すべてのメンバーが静的であるJavaの静的クラスに相当します。 そのクラスを持つCompanionオブジェクトは、Javaの静的メンバーが静的メンバーでも静的メンバーでもないクラスになります。 これを無効にすることはできません。 You can't do it in JavaあなたはScalaでそれを行うことはできません。

代替ソリューション:

だけクラスでtastyCultivarsを定義します。

abstract class Fruit(cultivar: String) { 
    val tastyCultivars: Set[String] 
    def isTastyCultivar(): Boolean = tastyCultivars.contains(cultivar) 
} 

class Apple(cultivar: String) extends Fruit(cultivar) { 

    val tastyCultivars: Set[String] = Set("Red Delicious", "Granny Smith") 
} 

class Tomato(cultivar: String) extends Fruit(cultivar) { 

    val tastyCultivars = Set("Roma") 
} 

val a1 = new Apple("Red Delicious") 
val a2 = new Apple("Honeycrisp") 

println("Should return true, is " + a1.isTastyCultivar()) 
println("Should return false, is " +a2.isTastyCultivar()) 

val t1 = new Tomato("Roma") 
val t2 = new Tomato("San Marzano") 

println("Should return true, is " +t1.isTastyCultivar()) 
println("Should return false, is " +t2.isTastyCultivar()) 

出力:型クラスについての私を教えるためのYuvalへ

$ scala fruit.scala 
Should return true, is true 
Should return false, is false 
Should return true, is true 
Should return false, is false 
+0

Javaの場合とは異なり、これは非常に可能で、 'object'sのメンバーをオーバーライドすることはできません。 –

0

感謝。私はすべての私の元の基準を満たす彼の技術を用いて溶液を書かれている:

// Fruit instance members 
abstract class FruitClass(cultivar: String) { 
    def getCultivar: String = cultivar 
} 

// Obviously not really an object but serves the purpose of 
// the thing I envisioned as the "abstract object" which is not a thing 
// I.e., a place to put fruit static members 
trait FruitObject[A <: FruitClass] { 
    // Any subclass of fruit must (statically) specify their set of tasty cultivars... 
    val tastyCultivars: Set[String] 
    // ...but they can inherit the common implementation of isTastyCultivar() 
    def isTastyCultivar(x: A): Boolean = tastyCultivars contains x.getCultivar 
} 

// Subclass #1: Apples 
class Apple(cultivar: String) extends FruitClass(cultivar) 
implicit object AppleIsFruit extends FruitObject[Apple] { 
    val tastyCultivars = Set("Red Delicious", "Granny Smith") 
} 

// Subclass #2: Tomatoes 
class Tomato(cultivar: String) extends FruitClass(cultivar) 
implicit object TomatoIsFruit extends FruitObject[Tomato] { 
    val tastyCultivars = Set("Roma") 
} 

def isTastyCultivar[A <: FruitClass: FruitObject](thing: A) = 
    implicitly[FruitObject[A]].isTastyCultivar(thing) 

isTastyCultivar(new Apple("Red Delicious")) // true 
isTastyCultivar(new Apple("Honeycrisp")) // false 
isTastyCultivar(new Tomato("Roma"))   // true 
isTastyCultivar(new Tomato("San Marzano")) // false 

Gustekはかなり右、そのオブジェクトのメンバーがオーバーライドすることはできませんですが、この方法は実際に果物のためのコンパニオンオブジェクトを使用せずに同じ効果を得るように思われます静的メンバーを宣言します。

+0

Yuval Itzchakovからの投稿は、「多くの感謝」を表明していますが、上告人でさえないのでしょうか?それは正しいとは思わないでしょう。 – jwvh

+0

明らかに理由があります。私は15人未満の記者がいる私のアップアップは表示されません。新しいアカウント –

関連する問題