2017-02-11 68 views
2

我有这个类最好的方法,从不同类别

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) 

UPD

对不起,伙计们。这个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 
} 

我试图简化 “的要求匹配” 块

+0

为什么不能延伸功能,只是调用'VAL U = X()'?用'apply'代替'execute'。 – Bergi

+0

我有一些遗留代码看起来像这样。我只能修改executeSomething及以下:( – HoTicE

+0

码你就不能使用重载executeSomething'高清executeSomething(X:美孚)= x.execute; 高清executeSomething(X:酒吧)?= x.execute' –

回答

6

虽然可以使用结构类型(鸭打字)实现它,它因为在运行时使用阶内省很大的开销。我认为实现它的最好方法是使用类型类。 Scala的Ordering就是一个例子。

A型类定义与“无关”类型相关联的功能。 你需要做的是在一个特点的形式定义类型类:

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

1

我想这和它的工作:

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 
3

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

Duck Typing更正式地称为Structural Types

A 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成员的类的实例。

+0

你用什么语言?斯卡拉没有'公共class',它需要'override'修饰符'FooFoo','BarBar',以及最重要的,招用'type'不起作用。 – dveim

+0

我实际上认为,因为OP公顷问这样一个很好的问题,提供的代码不会有这样明显的错误,比如' public'。而你其实并不“需要”来指定'override'。你这样做,作为一个很好的做法,以防止出错。 –

+0

@dveim它现在所有的工作。我没有忘记键入'='。它应该已经'输入HasExecuteMethod = {'。并且作为f或公共事物......我从OP的问题中复制粘贴,我没有注意到这些显而易见的问题。 –