我很困惑如何在Scala中解决这个问题 . 在Java中,我放弃了泛型或使用强制转换,但Scala比这更严格 . 这就是我所拥有的 .
-
一个抽象基类
Factory[+F <: Factory[F]]
和一些与此无关的具体实现 . 这是协变的 . 这个类有一个创建产品的方法 - 见下一点 . -
表示工厂产品的抽象基类
Product[+F <: Factory[F]]
. 这些也是协变和只读的 . 任何特定工厂只 生产环境 一种产品(即没有多种不同的子类型--FooFactory 生产环境 FooProduct,BarFactory 生产环境 BarProduct等) -
我必须有一个包含具体实例的工厂集合(Capt . 明显在这里说) . 目前这是
Iterable[Factory[_]]
. 这是麻烦的第一部分 . Scala似乎将_
理解为Any
,忽略了类型本身的约束F <: Factory[F]
. -
我有一个聚合工厂方法,要求每个工厂在给定相同参数的情况下 生产环境 其产品 . 结果是工厂到他们的产品的 Map ,目前编码为
Map[Factory[_],Product[_]]
,并尝试了Map[Factory[_],Product[Factory[_]]]
. 这是我遇到麻烦的另一部分 . 第一个_
与第二个_
取消链接,两者似乎都隐含为Any
.
我不能做的是创建该 Map . 它可能或不重要,但我通过使用另一种看起来像语法结构的方法来做(并且必须这样做) . 它来自一个特点:
-
调用获取工厂集合的声明方法(在此称为
gather[B](fun: A => B): Map[A,B]
,未在特征本身中实现并通常输入) . 实际的工厂类型是通用的和未知的 . -
迭代该泛型集合并执行传递给它的函数 . 这个函数实际上是调用工厂方法的 .
-
返回F到P的不可变
Map
编译器麻烦不在'gather'方法中,而是在调用它的代码中 . 我无法将其结果转换为 Map[Factory[_],Product[_]]
,因为_在任何一个地方都不符合 F <: Factory[F]
...我非常乐意使用 _
的基本类型,但那是 Factory[Factory[Factory[Factory......(infinitely many times)]]]]]]....
我不知道是什么去做 .
请帮忙!
学习者
4 回答
大多数情况下,在类型中使用
_
是不对的,除非你知道你在做什么 . 如果你不知道自己在做什么 . 并不是说Scala认为_
是Any
,它知道_
可以代表任何东西 - 无论是Any
,Nothing
还是介于两者之间的任何东西 .总结一下,
Iterable[Factory[_]]
表示Iterable[Factory[T]] forSome { type T }
. 您可以将其显式写为Iterable[Factory[T]] forSome { type T <: Factory[T] }
以获得所需的约束,就像您可以将其写为Map[Factory[T], Product[T]] forSome { type T <: Factory[T] }
一样 .不过,我不确定这是否真的是你需要的 . 您的问题主要集中在如何解决问题,而不是专注于如何解决问题 . 例如,可能更好的是使用以下代替泛型:
如果我的Scala有点生疏,请原谅我 . 我写的是一般的OOP和泛型意义 .
目前尚不清楚为什么
Factory
或Product
需要完全是泛型,很多协方差 . 无论是否实际需要,有一个简单的非泛型类FactoryBase
是必要和充分的,其中所有Factory
类最终都继承 . 你坚持到Iterable[FactoryBase]
.还不清楚为什么
Product
类型包含有关Factory
的任何信息 . 如果确实需要这些信息,那么相反的意义就更有意义了 .Factory
产生Product
,因此,知道它,所以这种知识可能会反映在类型中 . 然后,它可能不会 .如果您需要通用性,协方差和完整类型信息,您可以使用这样的层次结构:
您可以随意省略任何不需要的类型参数 .
还不清楚为什么需要将工厂映射到产品的 Map . Map 通常将名称之类的内容映射到实体 . 也就是说,给定名称,找到具有该名称的现有实体 . 工厂凭空创造新的 . 无论如何,如果你确实需要这样的 Map ,你可以使用
Map[FactoryBase, ProductBase]
. 这不提供静态保证FooFactory
映射到FooProduct
而不是BarProduct
,但Map
不能提供 . 然后,你可以在其各自的Factory
中粘贴一个Product
. 你已经知道编译时的映射,没有必要运行时Map
. 在n
,产品 生产环境 后不需要与任何工厂相关联 .也许我完全误解了你,你需要详细说明你的设计 . 因此,它的目的和架构根本不明确 .
我不太确定我理解你的问题,但尝试使用类似的东西:
添加另一个答案而不是编辑旧答案 .
我不一定会谈论Scala类型系统,因为这里的想法适用于许多不同的语言 .
首先,在谈论 Map 之前,让我展示如何 Build 更深层次的并行层次结构 . 这很简单,只需插入另一个级别:
您可以根据需要插入任意数量的级别 . 我们需要所有这些,包括非泛型
FactoryBase
和ProductBase
. 虽然它们并非严格必要,因为它们可以通过存在类型来逃避,但这些可能会变得笨拙 . 比(SomeFactory | exist F <: Factory[F,P], exist P <: Product[F,P], SomeFactory <: F)
更容易说FactoryBase
(这不是Scala语法,故意) . 有时存在是非常有用的,但不是在这个例子中(也许你可以在系统的其他部分使用它们) . 无论如何,这些FactoryBase
对象将被放置在Iterable[FactoryBase]
中以管理 生产环境 运行 .现在来到 Map . 有 生产环境 运行,在此期间每个工厂可以 生产环境 一个产品实例(或者可能没有) . 在工厂和 生产环境 运行期间,我们需要找到该工厂 生产环境 的产品 .
您尝试过一种解决方案:将 生产环境 运行表示为(或包含或其他)从工厂到产品的映射 . 在伪代码中暂时忽略类型:
如果我们坚持
FactoryBase
和ProductBase
,这甚至可能有用 . 但这种方法是有限的 . Map 将一堆类型A的东西映射到一堆(可能是不同的)类型B的东西 . 所有键都是类型相同的,并且所有值都是类型相同的 . 这显然不是我们所拥有的 . 所有工厂都有不同类型,所有产品也是如此 . 我们可以通过忘记部分类型信息来解决这个问题,也就是说,通过将键和值减少到最小公分母类型 . 但是如果我们稍后需要恢复这种类型的信息呢?这是不可能静止的,它被遗忘,永远失去 .另一个解决方案与第一个解决方案表面对称:工厂代表(或包含,在这种情况下)从 生产环境 运行到产品的映射 .
在这种情况下, 生产环境 运行仅由其唯一ID表示 . 但在类型级别,这种解决方案与第一种解决方案截然不同,而且要好得多 . 每个映射中的所有键都是类型相同的(实际上,它们在不同的工厂中都是类型相同的) . 每个映射中的所有值都是类型相同的(此类型特定于工厂) . 在任何阶段都没有丢失类型信息 .
所以,总结一下 . 有一个代表 生产环境 运行的类
PR
. 创建一个方法Factory[F,P].findProduct(pr:PR)->Product[F,P]
,通过Map[PR, Product[F,P]]
实现 . 让makeProduct
方法接受PR
值,并将生成的产品添加到 Map 中,并按PR
值键入 . 如果需要,可以将其包装在方法PR.lookUpProductByFactory[F,P](f:Factory[F,P])->Product[F,P]
或某些方法中 . 另外,将其包装在FactoryBase.findProduct(pr:PR)->ProductBase
中,并将其包装到PR.lookUpProductBaseByFactoryBase(f:FactoryBase)->ProductBase
中 .而已 . 我希望这两种解决方案能满足您的需求 .