在哪里找到某些功能 - 在对象类方法或应用程序代码中?

时间:2013-09-26 06:04:58

标签: oop

自从我触及面向对象编程以来已经很长时间了,所以我有点生疏,并且会很感激你的见解。

给定一个类,例如CDPlayer,包括字段numberOfTracks和currentTrack以及方法getCurrentTrack和setCurrentTrack,我应该在哪里设置将当前轨道设置为随机轨道的功能?在这个类中的setRandomTrack方法中,或者在这个类之外的应用程序代码中(例如player1.setCurrentTrack( randomnumbergeneratingcode ))?

这些方法的优点和缺点是什么?哪个更容易使用,更改和维护?上面的例子非常简单,但是当我想要时,事情如何变化,例如随机数生成要灵活 - 一个CDPlayer实例使用正态分布进行随机化,另一个使用平面分布,另一个使用由一组数字定义的分布,等等。

修改

感谢目前为止的三个回复。

考虑对操作的扩展...经过大量的编码后,很明显我们必须在应用程序代码中将当前的轨道更改为轨道三,但仅限于星期四(可能有非平凡的条件逻辑才能正常工作)。很明显,我们将不得不在开发过程中多次这样做。这个功能不会面向用户(就用户而言它是无用的),这只是我们需要在代码中多次设置的东西。

我们是否在类中创建了一个setThreeTracksBeforeOnThursdays方法并打破了这个类所拥有的CD播放器的紧密代表模型,或者我们是否完全坚持紧密的代表模型并将此功能保留在应用程序代码中,尽管它很痛苦添加到应用程序代码?设计是应该摇晃开发人员还是开发人员应该摇摆设计?

4 个答案:

答案 0 :(得分:0)

将它放入CDPlayer的专业是它将是一个单一的方法调用,并且该功能非常典型的CD播放器,所以它“感觉正确”。

将它放入你的应用程序的一个骗局是它需要两个调用,一个用于获取轨道数,因此你可以生成随机数,一个用来设置它。

将它放入CDPlayer的一个骗局是该类需要知道随机数。在这种特殊情况下,使用标准库很简单,但如果这是一个顶级安全CIA CD播放器可能是一个问题。 (刚注意到你的帖子暗示了类似的东西)

我将代码放在CDPlayer中,(并添加一个方法来更改随机数生成器,这个花哨的术语是依赖注入)但是这篇文章希望能给你一些优点和缺点。

答案 1 :(得分:0)

除了更具可读性之外,代码所在的位置没有任何实际好处。

但在某些情况下,将代码放入类中可能不那么多余,这完全取决于语言。例如:

班上的C#代码:

private Random random = new Random();

public void setRandomTrack()
{
    setCurrentTrack(random.NextInt());
}

课外的C#代码:

Random random = new Random();
CDPlayer player = new CDPlayer()
player.setCurrentTrack(random.NextInt());

外部代码必须在类外创建一个随机生成器来生成一个随机整数,如果它对你调用它的类不可见,你可能不得不多次创建随机生成器。

答案 2 :(得分:0)

  • 如果它是所有CD播放器都具有的功能,那么它应该在CDPlayer类中。
  • 如果它只是少数CD播放器所具有的功能,那么你应该继承CDPlayer类并将该函数放在子类中。
  • 如果它是没有CD播放器的功能,则没有理由将其包含在课堂中。 CDPlayer知道关于选择随机曲目是否有意义?如果没有,它应该在课外实施。

答案 3 :(得分:0)

让我们尝试实现此功能。播放随机曲目的要求是什么?

  • 它应该是随机的(当然),
  • 它应该不是当前曲目(如果还有其他曲目要播放,没有人想连续五次听到当前曲目)
  • 你应该从播放器中存在的那些中选择曲目(曲目编号不应超过曲目的数量)。

我将使用C#:

Random random = new Random();
CDPlayer player = new CDPlayer();
// creates list of track indexes, e.g. { 1, 2, 3, 4, 5, 6, 7 }
var tracksNotPlayed = Enumerable.Range(0, player.NumberOfTracks - 1).ToList();

if(tracksNotPlayed.Count == 0)
   // initialize list again, or stop

int index = random.Next(tracksNotPlayed.Count);
int nextTrack = tracksNotPlayed[index];
player.SetCurrentTrack(nextTrack);
tracksNotPlayed.Remove(nextTrack);

对我来说看起来像feature envy - 其他一些类使用来自播放器的数据来实现此功能。不好。让我们做一些重构 - 将所有这些东西都转移到播放器中:

public void PlayRandomTrack() // Shuffle
{
    if(tracksNotPlayed.Count == 0)
       tracksNotPlayed = Enumerable.Range(0, numberOfTracks - 1).ToList();

    int index = random.Next(tracksNotPlayed.Count);
    int nextTrack = tracksNotPlayed[index];
    SetCurrentTrack(nextTrack);
    tracksNotPlayed.Remove(nextTrack);         
}

它看起来更好,在外面使用更容易:

CDPlayer player = new CDPlayer();
player.PlayRandomTrack();

此外,如果您正在实现Winamp之类的东西(它有两种模式 - 随机播放和顺序播放,当它自动逐个播放歌曲时),那么考虑将此逻辑移动到某些Strategy(或者它应该是{ {3}}?),它将有两个实现 - 顺序和随机播放,并且对播放器一无所知 - 它的责任是在某个范围内选择数字(应该通过的轨道数或集合数):

public abstract class CollectionIterator<T>
{        
    public CollectionIterator(IEnumerable<T> source)
    {
       // save source
    }

    abstract int GetNextItemIndex();
}

玩家将使用此迭代器/策略来播放下一个项目:

public void PlayTrack()
{
    SetCurrentTrack(iterator.GetNextItemIndex());
}

因此,我们在这里明确分离责任 - 客户使用播放器听音乐,播放器知道如何播放音乐,迭代器知道如何从集合中选择下一个项目。如果你想在周四有其他序列,你可以创建ThursdaysCollectionIterator。这将保持您的播放器和客户端代码不受影响。