例如,假设您有一个控制台游戏程序,该程序具有往返于控制台的各种输入/输出方法。难道是聪明的,让他们在一个单一inputOutput
类或把它们分解到更具体的类,如startMenuIO
,inGameIO
,playerIO
,gameBoardIO
,等使得每个班大约有1-5的方法呢?
同时,如果最好将它们分解,将它们放置在IO
命名空间中是否明智,从而使它们更冗长,例如:IO.inGame
等?
例如,假设您有一个控制台游戏程序,该程序具有往返于控制台的各种输入/输出方法。难道是聪明的,让他们在一个单一inputOutput
类或把它们分解到更具体的类,如startMenuIO
,inGameIO
,playerIO
,gameBoardIO
,等使得每个班大约有1-5的方法呢?
同时,如果最好将它们分解,将它们放置在IO
命名空间中是否明智,从而使它们更冗长,例如:IO.inGame
等?
Answers:
由于我已经写了一个相当冗长的答案,所以这可以归结为:
inGameIO
和playerIO
类可能会违反SRP。这可能意味着您将处理IO的方式与应用程序逻辑结合在一起。我认为您在错误地看待这个问题。您正在根据应用程序组件的功能来分离IO,而-就我而言-根据IO的来源和“类型”拥有单独的IO类更有意义。
首先要有一些基KeyboardIO
类/泛型类MouseIO
,然后根据需要的时间和位置,来创建不同的子类来处理所述IO。
例如,您可能希望以与游戏内控件不同的方式来处理文本输入。您会发现自己想根据每个用例以不同的方式映射某些键,但是映射不是IO本身的一部分,而是您处理IO的方式。
坚持使用SRP,我有几个类可以用于键盘IO。根据情况,我可能希望与这些类进行不同的交互,但是它们的唯一工作就是告诉我用户在做什么。
然后,我将这些对象注入到处理程序对象中,该处理程序对象会将原始IO映射到我的应用程序逻辑可以使用的对象上(例如:用户按下“ w”,处理程序将其映射到上MOVE_FORWARD
)。
这些处理程序依次用于使角色移动并相应地绘制屏幕。过于简化,但要点是这种结构:
[ IO.Keyboard.InGame ] // generic, if SoC and SRP are strongly adhered to, changing this component should be fairly easy to do
||
==> [ Controls.Keyboard.InGameMapper ]
[ Game.Engine ] <- Controls.Keyboard.InGameMapper
<- IO.Screen
<- ... all sorts of stuff here
InGameMapper.move() //returns MOVE_FORWARD or something
||
==> 1. Game.updateStuff();//do all the things you need to do to move the character in the given direction
2. Game.Screen.SetState(GameState); //translate the game state (inverse handler)
3. IO.Screen.draw();//generate actual output
现在,我们有了一个负责原始形式的键盘IO的类。另一个将这些数据转换成游戏引擎可以实际理解的东西的类,然后使用该数据更新所涉及的所有组件的状态,最后,一个单独的类将处理输出到屏幕的内容。
每个类都有一个工作:处理键盘输入是由一个不知道/不关心/必须知道其处理意味着什么的类完成的。它所做的只是知道如何获取输入(缓冲的,未缓冲的...)。
处理程序将此信息转换为内部的表示形式,以供应用程序的其余部分使用此信息。
游戏引擎获取转换后的数据,并使用它来通知所有相关组件正在发生的事情。这些组件中的每一个都只做一件事,无论是碰撞检查还是角色动画更改,都没关系,这取决于每个对象。
然后,这些对象将其状态中继回去,并将此数据传递给Game.Screen
,从本质上讲,这是一个反向IO处理程序。它将内部表示映射到IO.Screen
组件可用于生成实际输出的内容上。
IO
和game
命名空间或带有子类的类吗?
单一责任原则很难理解。我发现有用的是像思考句子一样思考它。您不要试图将很多想法塞进一个句子中。每个句子应该清楚地陈述一个想法,并推迟细节。例如,如果您想定义一辆汽车,您会说:
一种由内燃机驱动的通常具有四个车轮的公路车辆。
然后,您将分别定义诸如“车辆”,“道路”,“车轮”等的内容。您不会尝试说:
一种用于在两个地方之间的道路,道路或道路上运输人员的车辆,该车辆已被铺设或以其他方式改进以允许行驶,该行驶具有四个圆形物体,这些物体在固定在车辆下方的车轴上旋转,并由产生动力的发动机提供动力通过与汽油,机油或其他燃料一起燃烧产生动力。
同样,您应该尝试使您的类,方法等尽可能简单地陈述中心概念,并将细节推迟到其他方法和类。就像写句子一样,对于句子的大小也没有硬性规定。
单一责任负责人指出,班级只应有一个变更理由。如果您的班级有多种变更原因,则可以将其拆分为其他班级,并利用合成来消除此问题。
要回答您的问题,我必须问您一个问题:您的班级只有一个改变的理由吗?如果没有,那么不要害怕继续添加更多的专业类,直到每个类只有一个改变的理由。