Bru*_*una 14 oop haskell functional-programming scala
我习惯于使用函数式编程(主要是Haskell),我从OO(scala)开始.
我在翻译代码时遇到了麻烦.例如,那是我对H树的B树定义:
data BTree a =
Leaf
|Node2 (BTree a) a (BTree a)
|Node3 (BTree a) a (BTree a) a (BTree a)
deriving (Eq,Read,Show)
Run Code Online (Sandbox Code Playgroud)
这很简单.我的树是空的,或者它有一个值,是两棵树的父亲,或者是3棵子树的父亲.
OO是什么?我没有线索.我无法弄清楚我怎么能以理智的方式做到这一点.
Dan*_*ral 18
这里有一些很好的答案,但我认为他们都错过了展示你所缺少点的机会.所以,你已经证明了这一点:
data BTree a =
Leaf
|Node2 (BTree a) a (BTree a)
|Node3 (BTree a) a (BTree a) a (BTree a)
deriving (Eq,Read,Show)
Run Code Online (Sandbox Code Playgroud)
并询问如何以面向对象的方式实现它.所以,这里是:
最重要的是
trait Tree[A] {
// not required because it is inherited from AnyRef
// def equals(other: Any): Boolean
// not required because it is inherited from AnyRef
// def toString: String
// does not belong in the object
// def fromString(input: String): Tree[A]
// Stuff that is missing but is needed
def isEmpty: Boolean
def value: Option[A]
def subtrees: Seq[Tree[A]]
def iterator: Iterator[A]
def depthFirstIterator: Iterator[A]
def breadthFirstIterator: Iterator[A]
}
Run Code Online (Sandbox Code Playgroud)
所以,这就是交易:当你谈到面向对象时,你有一个BTree,一个手指树,或者其他任何树结构是不相关的.事实上,它应该是隐藏的.相关的是你可以用它做什么.
你在这方面遇到了麻烦,因为你正是从你不应该的方向接近问题.
不那么重要的事情
sealed abstract class BTree[A] extends Tree[A]
object BTree {
def apply[A](input: String): BTree[A] = { /* factory */ null.asInstanceOf[BTree[A]] }
private case object Leaf extends BTree[Nothing] {
// method implementation
}
private case class Node2[A](value: A, private one: BTree[A], private two: BTree[A]) extends BTree[A] {
// method implementation
}
private case class Node3[A](value: A, private one: BTree[A], private two: BTree[A], private three: BTree[A]) extends BTree[A] {
// method implementation
}
}
Run Code Online (Sandbox Code Playgroud)
现在,您实际上提供了一个实现,但BTree的详细信息是完全隐藏的.您只能使用Tree
已定义的方法.
这是理想的面向对象架构:客户端依赖于接口,数据结构是隐藏的.
C. *_*ann 17
这是从功能性思维模式中获取OO的第一步:对象更像是函数而不是数据.想想他们就是这样; 而不是功能作用于透明的结构化数据,现在你有不透明的抽象行为.
从"好吧,这是我的数据的结构,现在我......"的角度来看它是向后的.
尝试这样的事情:
首先弄清楚可以用你的B树做什么基本动作(不要忘记这里show
和fmap
这里的事情)并根据这些来设计类.
对于像树这样的和类,可以更容易地将基类留空,并为数据构造函数的不同变体使用子类.作为OO的经验法则,您必须做出某种选择以大幅改变后续行为,强烈考虑使用子类型多态来区分案例.
在必要之前尽量不要担心内部表示,并且不要让表示细节从类中泄漏出来.拥有一堆返回原始类型的GetFoo()方法是"做错了"的标志.
最后:记住你正在使用Scala.出于某种原因,这是一种混合语言; 在OO风格中,并非一切都有意义.翻阅设计模式书,您会发现其中一半是关于缺少语言功能的巴洛克式高维护性解决方法.
Lan*_*nbo 12
由于您的标记列表中包含Scala,因此以下是在Scala中完成的操作:
你有一个基本特征(在Haskell中的类型),并从所有Haskell构造函数派生为case
类.这样你也可以在Scala模式匹配中使用它们.
sealed trait Tree[+A]
case object Leaf extends Tree[Any]
case class Node2[+A](a: A, t1: Tree[A], t2: Tree[A]) extends Tree[A]
case class Node3[+A](a: A, b: A, t1: Tree[A], t2: Tree[A], t2: Tree[A]) extends Tree[A]
Run Code Online (Sandbox Code Playgroud)
在Java(自1.5),C++和C#等语言中,您可以使用相同类型的模板来帮助键入安全性.它们基本上像Haskell中的类型变量一样工作.
此示例位于Scala中,但对于其他OO语言,您可以采用类似的方式执行此操作:创建抽象基类并将数据的构造函数转换为类/对象.
归档时间: |
|
查看次数: |
945 次 |
最近记录: |