我们的Web服务接口的一部分,我们创建了更轻量级的面向客户端的API,这些API不依赖于任何特定的平台/供应商API。
现在,这些服务特征的impl必须将这些承载传入数据的平台不可知类型转换为供应商特定类型,以便impl方法继续按原样工作。请注意,我们无法更改供应商API上的任何代码。我想我们必须创建某种适配器/转换API,可以双向进行这种类型的转换。一些供应商类型非常神秘。例如较轻的服务接口可以具有包含所有数据的展平类型,而供应商API具有可以获取输入数据的分层类型等。返回类型的情况也是如此。在Scala中实现这一目标的最佳方法是什么?
编辑:示例
case class A(var1,var2,var3,var4,var5,var6)
public Class B{
private C c;
private D d;
}
案例类是一个扁平化结构,需要所有数据,而另一方面,来自类A类的数据将填充为B(var2,var3),C(var4,var5),D(var6)等。我忘了提到供应商API都是基于Java的。
谢谢,
答案 0 :(得分:0)
我想说你可以利用“Pimping”模式在两者之间来回走动。这是我在我的应用程序中使用的一大块东西。我只转换一种方式,但你可以看到另一种隐含的方式,你可以实现逻辑回到原始/你的格式。
// implicits for pimping
implicit def pimpUser(user: User) = PimpedUser(user)
implicit def pimpLimitedViewUser(user: LimitedViewUser) = PimpedLimitedViewUser(user)
@entity
case class User(@serializer(classOf[UUIDOptionSerializer]) @id @column(name = "id") override val id: Option[UUID] = None,
@serializer(classOf[DateOptionSerializer]) @column(name = "created_on") override val createdOn: Option[Date] = None,
@serializer(classOf[DateOptionSerializer]) @column(name = "modified_on") override val modifiedOn: Option[Date] = None,
@serializer(classOf[StringOptionSerializer]) @column(name = "first_name") firstName: Option[String] = None,
@serializer(classOf[StringOptionSerializer]) @column(name = "last_name") lastName: Option[String] = None,
@serializer(classOf[StringOptionSerializer]) @column(name = "email_address") emailAddress: Option[String] = None,
@serializer(classOf[StringOptionSerializer]) @column(name = "password_salt") passwordSalt: Option[String] = None,
@serializer(classOf[StringOptionSerializer]) @column(name = "password_hash") passwordHash: Option[String] = None,
@serializer(classOf[IntOptionSerializer]) @column(name = "extension") extension: Option[Int] = None,
devices: Set[Device] = Set.empty,
@serializer(classOf[RingModeSerializer]) @column(name = "ring_mode") ringMode: RingMode = Waterfall) extends IdBaseEntity[UUID] {
def this() = this(None, None, None, None, None, None, None, None, None, Set.empty[Device], Waterfall)
override def equals(other: Any): Boolean =
other match {
case that: User => (that canEqual this) && (this.id match {
case Some(uuid) => that.id match {
case Some(thatUuid) => uuid == thatUuid
case None => false
}
case None => false
})
case _ => false
}
override def hashCode: Int = this.id match {
case Some(uuid) => 41 * (41 + uuid.hashCode())
case None => super.hashCode
}
override def canEqual(other: Any): Boolean = other.isInstanceOf[User]
def asAvailable: User = {
User.devices.set(this)(devices.map(_.asAvailable))
}
def asUnavailable: User = {
User.devices.set(this)(devices.map(_.asUnavailable))
}
}
object User {
implicit val userIso = Iso.hlist(User.apply _, User.unapply _)
val id = Lens[User] >> _0
val createdOn = Lens[User] >> _1
val modifiedOn = Lens[User] >> _2
val firstName = Lens[User] >> _3
val lastName = Lens[User] >> _4
val emailAddress = Lens[User] >> _5
val passwordSalt = Lens[User] >> _6
val passwordHash = Lens[User] >> _7
val extension = Lens[User] >> _8
val devices = Lens[User] >> _9
val ringMode = Lens[User] >> _10
}
case class LimitedViewUser(id: Option[UUID], createdOn: Option[Date], modifiedOn: Option[Date], firstName: Option[String], lastName: Option[String]) {
def this(user: User) = this(user.id, user.createdOn, user.modifiedOn, user.firstName, user.lastName)
}
case class PimpedUser(underlying: User) {
def limited = LimitedViewUser(underlying)
}
case class PimpedLimitedViewUser(underlying: LimitedViewUser) {
def normal = /* do something here to transform back to yours/the normal one */
}
// As long as those implicits are brought into scope, you will be able to do this:
val user: User = /* ... */
val limitedViewUser: LimitedViewUser = user.limited
val normalUser: User = limitedViewUser.normal