簡體   English   中英

對象擴展特性,類擴展特性,都必須實現方法

[英]Object extends Trait, Class extends Trait, both have to implement method

我有以下設置:

trait A
{
  def doSomething(): Unit;
}

object B extends A
{
 override def doSomething(): Unit = 
 {
   // Implementation
 }
}

class B(creator: String) extends A
{
 override def doSomething(): Unit =
 {
   B.doSomething() // Now this is just completely unnecessary, but the compiler of course insists upon implementing the method
 }
}

現在您可能想知道為什么我什至這樣做,為什么我還要讓班級也擴展特質。

問題是,程序中某處有一個A的集合。所以某處:

private val aList: ListBuffer[A] = new ListBuffer[A]

在那兒,我還必須放入Bs(以及其他派生詞C和D)

所以我不能只是讓B級不擴展它。

由於所有實例的實現都相同,因此我使用一個對象。

但是還有一個原因我真的需要這個對象。 因為有一個類:

abstract class Worker
{
 def getAType(): A

 def do(): Unit =
 {
   getAType().doSomething()
 }
}

class WorkerA
{
  def getAType(): A =
  {
    return B
  }
}

此處返回B的單例/對象。 這是在Worker中實現do()所必需的。

總結一下:

因為do()(Worker-Class)中的通用實現以及doSomething()從未更改,所以需要對象B。

需要類B,因為在BaseType A的集合中,有不同的B實例且作者不同。

由於上述原因,對象和類都必須實現特征,因此我在這里遇到了兩難選擇。 我找不到看起來更整潔的令人滿意的解決方案。

所以,我的問題是 (原來是非母語人士,我應該對此進行更多澄清)

有沒有辦法讓一個類擴展一個特征(或類),並說應該在對象而不是該類中查找任何抽象方法的實現,所以我只能實現“ doSomething()”(從特征中實現)。 )一次(在對象中)? 正如我所說,特質在這里完成了兩項不同的任務。 一種是BaseType,以便集合可以獲取該類的實例。 另一個是確保doSomething()方法存在於每個對象中的合同。

因此,對象B 需要擴展特征,因為特征就像Java接口一樣,並且每個(!)對象B(或C或D)都需要具有該方法。 (因此,我看到的唯一選項是->定義接口/特征並確保該方法在那里)

編輯 :萬一有人想知道。 我如何真正解決問題:我實現了兩個特征。

現在,對於一個班級(我需要的地方),我將兩者都擴展,而對於另一個班級,我只會擴展一個。 因此,我實際上不必執行並非絕對必要的任何方法:)

正如我在評論部分中所寫的那樣,我真的不清楚您要問什么。 但是,在您的代碼示例中,對我來說似乎並沒有真正需要trait A 您可以使用Scala SDK隨附的類型:

object B extends (()=>Unit) {
  def apply() { /* implementation */ }
}

或者,作為變體:

object B {
  val aType:()=>Unit = {() => /* implementation */ }
}

在第一種情況下,您可以使用B訪問單例實例,在第二種情況下,可以使用B.aType 在第二種情況下,不需要顯式聲明apply方法。

選擇你喜歡的。 基本信息是:僅定義一個簡單方法就不需要特征。 這就是Scala函數的作用。

列表類型可能如下所示:

private val aList:ListBuffer[()=>Unit] = ???

(順便說一句:為什么不將其聲明為Seq[()=>Unit] ?對於調用者來說,它是一個ListBuffer而不是其他某種序列對您來說重要嗎?)

然后,您的工作者可能看起來像這樣:

abstract class Worker {
  def aType:()=>Unit // no need for the `get` prefix here, or the empty parameter list
  def do() {aType()}
}

請注意,現在Worker類型已經成為提供調用函數的方法的類。 因此,實際上並不需要Worker類。 您可以直接采用函數( aType )並調用它。

如果您始終想調用object B的實現,那就好了。 無需將調用包裝在其他類型的實例中。 您的示例類B只是將調用轉發給B對象,這實際上是不必要的。 甚至不需要創建B的實例。 它確實具有private成員變量creator ,但由於從未使用過,因此絕不會以任何方式對其進行訪問。

因此,我建議完全刪除class B 您只需要類型()=>Unit ,這正是您所需要的:一個不帶參數且不返回任何值的函數。

如果您一直不厭煩編寫()=>Unit ,則可以定義類型別名,例如在package對象內部。 這是我的建議:

type SideEffect = ()=>Unit

然后,您可以將SideEffect用作()=>Unit的別名。

這就是我所能做的。 在我看來,這可能不是您想要的。 但這也許會在整個過程中對您有所幫助。 如果您想得到一個更具體的答案,那么請您澄清問題。

除了某些特殊規則外, object B確實與class B不大。

如果您希望重用該doSomething方法,則應僅重用該對象的實現:

class B {
  def doSomething() = B.doSomething()
}

如果要將object B指定為class B的特定實例,則應執行以下操作:

object B extends B("some particular creator") {
...
}

您也不需要override修飾符,盡管它們可以方便地進行編譯器檢查。

擴展特征的伴侶對象的概念對於定義與類本身(例如靜態方法)相關聯的行為(而不是類的實例)很有用。 換句話說,它允許您的靜態方法實現接口。 這是一個例子:

import java.nio.ByteBuffer

// a trait to be implemented by the companion object of a class
// to convey the fixed size of any instance of that class
trait Sized { def size: Int }

// create a buffer based on the size information provided by the
// companion object
def createBuffer(sized: Sized): ByteBuffer = ByteBuffer.allocate(sized.size)

class MyClass(x: Long) {
  def writeTo(buffer: ByteBuffer) { buffer.putLong(x) }
}
object MyClass extends Sized {
  def size = java.lang.Long.SIZE / java.lang.Byte.SIZE
}

// create a buffer with correct sizing for MyClass whose companion
// object implements Sized. Note that we don't need an instance
// of MyClass to obtain sizing information.
val buf = createBuffer(MyClass)

// write an instance of MyClass to the buffer.
val c = new MyClass(42)
c.writeTo(buf)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM