【问题标题】:Best way to run common function from different classes从不同类运行通用功能的最佳方式
【发布时间】:2017-06-29 23:46:36
【问题描述】:

我有这门课

public abstract class Foo {
    def execute: Unit = ???
}

public abstract class Bar {
    def execute: Unit = ???
}

public class FooFoo extends Foo {
    def execute: Unit = ???
}

public class BarBar extends Bar {
    def execute: Unit = ???
}

在我有这种方法的地方:

def executeSomething(body: => AnyRef) : = Try(body) match ...

电话看起来像这样

x match {
  case _: Foo => executeSomething(x.execute)
  case _: Bar => executeSomething(x.execute)
}

有什么方法可以让我这样做(没有新课程)

val u = executeSomething(x)

?

更新

对不起,伙计们。这个 m.b.真实的代码会更清晰

import akka.actor.{Actor, ActorLogging, ActorRef, Props}
import com.google.api.client.auth.oauth2.AuthorizationCodeTokenRequest
import com.google.api.client.googleapis.json.GoogleJsonResponseException
import com.google.api.services.analytics.Analytics
import com.google.api.services.analyticsreporting.v4.AnalyticsReporting
import com.my.lab.messages.{GRequest, GResponse}
import scala.util.{Failure, Success, Try}

class GQueueTask(req: GRequest, ref: ActorRef) extends Actor with ActorLogging {

  def receive: Receive = {
    case _ =>
  }

  def execute(body: => AnyRef): Unit = {
    Try(body) match {
      case Success(r) => ref ! GResponse(req, response = Option(r))
      case Failure(f: GoogleJsonResponseException) =>
            f.printStackTrace()
            ref ! GResponse(req, error = Option(f))
      case _ => ref ! GResponse(req, Option("unknown error"))
    }
  }

  req match {
    case GRequest(request, _) => request match {
      case x: AnalyticsReporting#Reports#BatchGet => execute(x.execute()) // AbstractGoogleClientRequest
      case x: Analytics#Data#Ga#Get => execute(x.execute()) // AbstractGoogleClientRequest
      case x: Analytics#Management#Accounts#List => execute(x.execute()) // AbstractGoogleClientRequest
      case x: Analytics#Management#Webproperties#List => execute(x.execute()) // AbstractGoogleClientRequest
      case x: Analytics#Management#Profiles#List => execute(x.execute()) // AbstractGoogleClientRequest
      case x: AuthorizationCodeTokenRequest => execute(x.execute()) // TokenRequest
      case _ => ref ! GResponse(req)
    }
  }

  context stop self
}

我试图简化“请求匹配”块

【问题讨论】:

  • 为什么不扩展 Function 而只是调用val u = x()?使用apply 而不是execute
  • 我有一些遗留代码看起来像这样。我只能修改下面的executeSomething和代码:(
  • 你不能只使用重载的executeSomething吗? def executeSomething(x:Foo) = x.execute; def executeSomething(x:Bar) = x.execute?
  • x 是什么? Try(Body) 的结果?您能否重新阅读您的问题并使其更清楚。

标签: scala types functional-programming


【解决方案1】:

虽然你可以通过使用结构类型(鸭子类型)来实现它,但它有很多开销,因为 scala 在运行时使用自省。我认为实现它的最佳方法是使用类型类。它在 Scala 中到处都在使用 :) Scala 的 Ordering 就是一个例子。

类型类定义与“不相关”类型相关的功能。 你需要做的是以 trait 的形式定义类型类:

trait Executable[T] {
    def execute(t: T): Unit
}

你需要让你的类型成为该类型类的成员,例如:

implicit object FooFooExecutable extends Executable[FooFoo] {
  override def execute(t: FooFoo): Unit = t.execute()
}

最后一件事是定义将你的类型类作为参数的方法。

def exec[T: Executable](t: T): Unit = {
  implicitly[ExecTypeClass[T]].execute(t)
}

您可以阅读更多关于类型类hereherehere

【讨论】:

    【解决方案2】:

    这看起来是duck-typing 的一个很好的用例。

    Duck Typing 更正式地称为Structural Types

    Duck Type 可以被认为只是一组所需属性的specificationCompile time reflection 用于确保提供的参数的type 与您的duck-typespecification 兼容。因此它为您提供编译时类型安全。

    然后它使用run time reflection 在提供的实例上实际调用相应的方法。

    所以,

    假设您有以下抽象,

    abstract class Foo {
      def execute(): Unit
    }
    
    abstract class Bar {
      def execute(): Unit
    }
    
    class FooFoo extends Foo {
      override def execute(): Unit = {
        println("FooFoo")
      }
    }
    
    class BarBar extends Bar {
      override def execute(): Unit = {
        println("BarBar")
      }
    }
    

    注意 :: 我已将 () 添加到您所有的 Unit 方法中。这是 Scala 中的一个约定,即所有具有副作用的方法都应该有()。而Unit 方法除了副作用之外不能做任何事情。

    现在...您只需为共享行为定义一个duck-type

    type HasExecuteMethod = {
      def execute(): Unit
    }
    

    现在...让我们定义一个使用这种鸭子类型的函数,

    def doExecute(hasExecuteMethod: HasExecuteMethod): Unit = {
      hasExecuteMethod.execute()
    }
    

    还有……给你。这个doExecute 方法将接受任何具有def execute(): Unit 成员的类的实例。

    【讨论】:

    • 您使用什么语言? Scala 没有public class,它需要FooFooBarBar 中的override 修饰符,最重要的是,type 的技巧不起作用。
    • 其实我还以为OP ha问了这么好的问题,提供的代码就不会出现public这样明显的错误了。而且您实际上并不“需要”指定override。你这样做是防止错误的好习惯。
    • @dveim 现在一切正常。我确实忘记输入=。应该是type HasExecuteMethod = {。至于公共的事情......我从OP的问题中复制粘贴,我没有注意到这些明显的问题。
    • @dveim 现在我已经修复了它。能否请您删除 trick with type does not work 部分,以便提出此问题的人可以了解 duck-typing
    • 感谢您修复这些语法问题。 trick with type does not work 我的意思是 1)语法错误(所以 REPL 不起作用)2)我不知道可以用这种方式描述结构类型 :) 只是为了清楚起见,你能补充一下吗你的答案使用反射?
    【解决方案3】:

    我试过了,效果很好:

    object Dummy {
      abstract class Foo {
        def execute: Unit
      }
    
      abstract class Bar {
        def execute: Unit
      }
    
      class FooFoo extends Foo {
        def execute: Unit = { println("Foo") }
      }
    
      class BarBar extends Bar {
        def execute: Unit = { println("Bar") }
      }
    
      def run(x: AnyRef): Unit = {
    
        x match {
          case f: Foo => f.execute
          case b: Bar => b.execute
          case _ =>
        }
      }
    
      def main(args: Array[String]): Unit = {
        val any = new BarBar()
        run(any)
      }
    }
    

    打印出来了

    Bar
    

    【讨论】:

      猜你喜欢
      • 2011-02-07
      • 1970-01-01
      • 1970-01-01
      • 2019-03-03
      • 1970-01-01
      • 2017-11-11
      • 1970-01-01
      • 2020-12-04
      • 2013-07-29
      相关资源
      最近更新 更多