首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >解耦问题

解耦问题
EN

Software Engineering用户
提问于 2018-05-24 10:25:34
回答 5查看 1.1K关注 0票数 5

这是我在当前项目中所面临问题的简化版本。

假设我们想要显示形状:矩形、圆圈等等。我将有一个形状类,它是由矩形、圆圈等子类组成的。然后我将有一个World类,它表示一个包含不同坐标下形状的2d平面。我将通过world.add(shape, x, y)向世界添加形状。这个世界对象和它的孩子应该完全不知道,我正计划在屏幕上显示他们。

现在我要展示这个。由于我可能会改变主意,我使用的图形库,我将有一个单独的Visualizer类。我用new Visualizer(world)创建一个,然后调用visualizer.show()。如果我更改图形库,我将创建一个不同的Visualizer类。

现在,这段代码中的某个地方是一个显示矩形的函数,另一个是显示圆圈的函数。他们应该去哪里?

  1. 在矩形和圆圈类中?但是现在,形状类不仅要知道它们正在被绘制,还必须知道我使用的绘图库是什么。如果我经常更改库,矩形类将积累大量的Rectangle.library1Plot()Rectangle.library2Plot()方法。
  2. 在显像机里?但是现在Visualizer必须知道所有不同的形状子类,它不能仅仅把形状当作形状来封装它是什么样的形状。我必须打开Shape子类,然后使用.plotRectangle.plotCircle方法,在创建更多的形状类型时添加越来越多的方法。

这两种解决方案对我来说都不合适。

在代码中的某个地方,某人必须同时访问两条信息:形状是什么子类,以及我使用的图形库。哪里是最好的地方?

EN

回答 5

Software Engineering用户

发布于 2018-05-24 12:58:44

如果形状类知道如何将自己绘制到某物上是可以接受的(而不知道下面使用的是哪个输出设备或图形库),那么您可以引入一个VisualizerInterface接口,该接口提供绘制简单线条和弧线的功能。

Visializer类将实现VisualizerInterface,并将绘制直线或弧线的函数转换为对特定图形库的正确调用。

Shape类将使用VisualizerInterface将自己绘制到任何可能的Vizualizer中,而不知道底层图形库。

Visualizer::show()方法可能类似于

代码语言:javascript
复制
Visualizer::show() {
  foreach(shape in world.get_shapes()) {
    shape.draw(this)
  }
}

其中,从形状派生的每个类都会重写绘图方法。

票数 5
EN

Software Engineering用户

发布于 2018-05-24 12:51:00

我建议第三种选择:将描述形状的过程与绘制形状的过程分开。

有一个系统的描述一个形状的绘制,根据一个列表的直线和弧定义。然后,每个形状都有责任根据这些线定义来定义自己。

然后,可视化工具负责将一组线条描述转换为呈现的形状。

这样,形状就不需要知道任何关于如何呈现自己的信息,而可视化工具也不需要知道任何关于单个形状的信息。您完全避免了“代码中的某个位置,某人必须同时访问两个信息:形状是什么子类,以及我正在使用的图形库”的情况。可视化工具只在它提供的任何形状上调用shape.GetDrawingInstructions()。然后将耦合简化为一种方法,以及一组指令所采用的任何格式。

票数 3
EN

Software Engineering用户

发布于 2018-05-24 17:35:59

我用模型/视图/视图模型(Model/ViewModel,MVVM)体系结构完成了您正在讨论的内容。只要您的呈现支持此设计模式(即支持绑定),它就可以工作。问题是,您将有许多您正在使用的视图。

模型代表被代表的事物。在我的例子中,它是一个映射应用程序。我们有特定于应用程序的对象和用户对象,它们帮助用户更好地总结地图。由于位置(即lat/lon)是模型的关键要素,我们在这里包括了这一点。

ViewModel负责诸如颜色之类的事情,在某些情况下切换表示(即表示某物的图标)。视图模型适用于不同类别的事物。也就是说,某物是地图上的一个特定点(针垫或自定义图标)、一个区域(多边形)、一条线还是一个椭圆。这些东西在我们的应用程序中有着特殊的意义,所以它们必须得到支持。

视图实际上负责在屏幕上呈现对象。这是唯一特定于平台的部分(即XAML与UAP相对于其他部分)。我们确实需要创建一个自定义面板来呈现控件(以及优化,这样它就不会在视图范围之外的事情上浪费时间)。

使这成为可能的是将属性从ViewModel和模型绑定到视图的能力。我们的代码存在于视图层中,这些代码将更具体的视图与相应的ViewModel匹配。

当然,这是大量的代码,但是如果您想在不显示映射的情况下运行模拟,这是可能的。您只需执行模型层和VieModel层。

如果您实际上需要有绘图指令,则另一个选项仍然是继续制作ViewModel,但是有一个抽象的Draw(Canvas)方法。然后,您必须为您需要的特定呈现代码对ViewModels进行子类化。或者,您可以创建一组原语,这些原语以绘图指令的形式组装。

作为绘制的一般规则,您可以使用以下2D原语:

  • 线路
  • 矩形
  • 多边形
  • 椭圆
  • 圆弧
  • 文本

你的3D等价物和那些基本形状没有太大的不同。

票数 1
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/371474

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档