重构;如何使一个班级对另一个班级一无所知?

时间:2018-10-16 14:47:16

标签: c# refactoring

快速笔记

此问题不依赖于基于3D的代码,也不依赖于逻辑;它只是着重于消除一个对象与另一个对象之间的依赖关系,因此,我在描述问题时会尽量做到透彻。虽然具有3D背景知识可能会有助于理解代码的作用,但不需要将A类与B类分开。我相信可以通过一些逻辑但横向的思考来解决此任务。


概述

我正在重构一些旧代码(在90年代初的某个时候编写),并且有一些类依赖于其他类。这个问题将集中在依赖于另一个单独类的单个类上(在这种情况下,没有其他依赖项)。该项目是DirectX项目,它只是将一些对象渲染到屏幕上以用于工作目的。不幸的是,我无法给出详尽的描述。但是,我可以用代码解释问题。

我需要重点关注两个类,由于我们现在对渲染存在第二需求,因此我目前正在重写其中一个类,以使其具有通用性和可重用性。

  • Engine3D(当前正在重写)
  • Camera3D

我将在下面更详细地说明,但是情况的要点是Engine3DCamera3D方法中依赖于Render


Engine3D的当前流量

Engine3D的当前流程主要集中在实现一个目标上。呈现项目所需的东西,就是这样。

public void Render() {
    // Clear render target.
    // Render camera.
    // Set constant buffers.
    // Render objects.
    // Present back buffer.
}

更新代码和渲染代码都混杂在一起,并且渲染到屏幕上的每个对象都位于Render方法中。这对可重用性不利,因为它会强制每次渲染完全相同的场景。因此,我将其分解,创建一个通用的Engine3D,然后在我的代码(我们称之为Form1)中使用它。


新流程

通过将Draw调用到Engine3D并传入要渲染的对象,使渲染对象到屏幕成为一个简单的任务。与XNA Framework的过去很像。 Engine3D的新流程的基本表示是:

// I may move this to the constructor; if you believe this is a good idea, please let me know.
public new virtual void Initialize() {
    base.Initialize();
    OnInitialize(this, new EventArgs());

    RenderLoop.Run(Window, () => {
        if (!Paused) {
            OnUpdate(this, new EventArgs());
            Render();
        }
    });
}
protected override void Render() {
    // Clear Render Target. context.ClearRenderTargetView(...);
    // Set constant buffers.
    OnRender(this, new EventArgs());
    // Present back buffer.
}

OnUpdate用于更新屏幕上的任何对象,而OnRender将处理新的Draw调用。


问题

问题是旧的流程(在渲染循环内)清除了渲染目标,然后渲染了摄影机,然后开始设置常量缓冲区。我已经很轻松地完成了该列表中的第一个,该列表中的第二个是使用新流程的简单Draw调用(可以在设置缓冲区之后进行);但是问题在于设置了常量缓冲区。以下代码行需要Camera3D对象,而在移动该对象时遇到了问题。

ConstantBuffers.PerFrame perFrame = new ConstantBuffers.PerFrame();
perFrame.Light.Direction = (camera.TargetPosition - camera.Position);
perFrame.CameraPosition = camera.Position;
perFrame.CameraUp = camera.Up;
context.AddResource(perFrame);

然后将此变量添加到渲染目标的资源列表中,该资源必须保留在Engine3D中,以防止绘制代码过于复杂。

代码中稍后还有其他对象依赖于Camera3D的{​​{1}}属性,但是一旦我解决了如何将WorldEngine3D分离开来,我确保我可以轻松地照顾其余的人。


问题

如何将这种依赖性与Camera3D类分开?

我想到的一些事情是:

  • 创建一个方法来设置在绘制之前必须调用的缓冲区。
  • 将这些属性在Engine3D上设为静态,因为总有一个摄像头,再也没有。
  • 创建专门用于处理此问题的相机的方法。
  • 创建一个中间人类来处理所有这些问题。
  • 合并Camera3DEngine3D类。

如果对我要达到的目标感到困惑,请告诉我,我将尽力而为。

1 个答案:

答案 0 :(得分:1)

您要进行的重构称为 Pure Fabrication


您建议的解决方案是:

  

在Camera3D上将这些属性设为静态,因为总是有一个摄像机,再也没有。


我建议:

  • 您可以创建另一个类(将其命名为StudioSetup),该类包含Engine3D中需要的字段(并且您希望在Camera3D中使其成为静态对象) );
  • 使用当前值填充该类的对象,并将其传递给Engine3D->Render();
  • 现在,对Camera3D的依赖已替换为对StudioSetup对象的依赖。

这类似于您的“创建一个中间人类来处理所有这些”。解。但是,中间人除了做单向快递员以外,不会做任何事情。