Scala:UI 对象/渲染器的设计模式

Scala: Design pattern for object / renderer for UI

如果有 rendererobject 会是一个好的设计。

我已经做了几次尝试,但我的代码现在真的很难看。

假设我有一个 class room 和一个 class 应该处理渲染它。

如何构建简单的单元测试,例如 renderer.render(room, userInteraction)

return 应该是什么?

world.renderRoom().interact()....

如你所见,我不知道该怎么办哈哈。

我有几年编写软件的经验,但我正在尝试 ScalaZ 并努力变得更像 functional-programming;这对我来说是新的。

谢谢

渲染屏幕不是一个纯粹的函数,因为它有副作用。阅读 IO monad

您会发现大多数(如果不是全部)示例都围绕 println 和 readln,但适用相同的原则。在 scalaz 的上下文中,请查看 ZIO.

如果 Tim 在评论中建议,渲染是一个纯函数,那么我建议渲染是模型渲染(房间)的函数,房间状态是动作的折叠 newRoomState=actions.foldLeft(oldRoomState)(state,action => someFunction(s,a))(油漆墙,加沙发什么的)见SAM pattern。接受渲染的世界(flatMaps/reduce 超过多个渲染?!)是保证 IO monad 的部分)

你似乎问了很多不同的事情,这使得除了非常笼统的方式外很难回答。

不要向数据对象添加呈现代码,因为这会破坏关注点分离。 classic OO 示例 Shape class 和 draw 方法非常适合教学,但它将有关形状(例如边数)的数据与具体绘制方法。相反,创建一个函数 render(s: Shape),它使用 Shape 中的数据以您想要的特定方式绘制(2D、3D 填充、坐标列表等)。

使您的 render 代码具有功能性,以便它 return 渲染数据而不是调用渲染库作为副作用。渲染库需要具有功能性,并且 return 渲染结果而不是直接绘制到屏幕上。

将渲染库传递给 render 函数(作为 implicit 参数)而不是使用全局对象。这允许您使用模拟渲染器测试渲染,并且无论如何都是一种更灵活的设计。但是对于不同的输出设备或样式,您可能仍然需要不同的 render 函数。

将渲染与渲染组件的组合分开,以便您可以独立测试它们。

以功能方式构建整个图像,然后通过单个非功能操作来显示新图像(通过替换当前图像)。

使用用户交互创建一个更新后的场景 room,然后重新渲染整个场景。

TL;DR

val room = Room(width, length, height)
val room3D = render(room, render3D)
val house = compose(room3d, ..., compose3D)

screen.display(house)