.NET Stream类的设计不良吗? [关闭]

问题描述 投票:18回答:9
我花了很多时间来熟悉.NET Stream类。通常,我会通过学习专业的商业级框架的类设计来学到很多东西,但是我不得不说,这里没有什么味道。

System.IO.Stream是代表字节序列的抽象类。它具有10个抽象方法/属性:Read, Write, Flush, Length, SetLength, Seek, Position, CanRead, CanWrite, CanSeek。如此众多的抽象成员使派生繁琐,因为您必须重写所有这些方法,即使大多数方法最终只是抛出NotImplemented

Stream类的用户应该调用CanReadCanWriteCanSeek来了解Stream的功能,或者我想继续调用ReadWrite或[C0 ],然后查看是否抛出Seek。是我一个人,还是这个笨拙的设计?

尽管我想在NotImplemented类设计中挑选很多尼特,但我想问的主要问题是:他们为什么不使用接口,例如StreamIReadableIWriteable,而不是?然后,可以从其支持的接口优雅地派生新的Stream类。这不是面向对象的做事方式吗?还是我错过了什么?

更新:指出ISeekable etal值可以在运行时更改,例如,如果CanRead关闭,则可以获取该点。但是,我仍然不相信这是一个好的设计。我来自哪里,尝试从已经关闭的文件中读取是一个错误,或者至少是一个例外情况。 (因此抛出异常是处理这种情况的自然方法。)

这是否意味着我每次要从FileStream转到Read时,都应该检查Stream?如果在CanRead调用和CanRead调用之间的某个时间值可能发生变化,那是否意味着我应该锁定以避免竞争的条件?

2010年8月7日更新]:此处的共识似乎是Stream设计非常好。但是让我再问一次,以确保100%确信:人们每次从Stream中读取内容时都在写类似的东西吗?Read

我花了很多时间来熟悉.NET Stream类。通常,我通过研究专业的商业级框架的类设计学到很多东西,但是我不得不说...
c# .net oop stream abstract-class
9个回答
10
投票
我认为这些类的设计很好。我宁愿检查一个属性,然后尝试做某事并必须捕获异常。在具有多个“类型”的流类型的情况下,接口不足。使您获得可读和可写流的方法将返回什么类型?我同意设计不是真正的面向对象的设计,但是您真的要以这种方式对待流吗?如果关闭了流或某些其他更改,某些属性可能会更改,在这种情况下会发生什么?

9
投票
使用接口将意味着在运行时无法更改“ CanRead”的值。 “ FileStream”类根据文件的当前状态更改“ CanRead”属性。

7
投票
他们可能没有使用接口,因为当时没有扩展方法。如果您希望每个流都具有默认的ReadByte方法之类的东西,则需要使用一个类。

5
投票
接口可能会被过度使用,这就是其中一种情况。我认为目前的设计很棒。流可以在运行时更改功能的事实意味着IReadable / IWritable / ISeekable不会消除对CanRead,CanWrite和CanSeek的需求,因此,除了消除少数存根方法和属性外,您实际上只会增加复杂性而没有任何实际收益在您的派生类中。

4
投票
Class Stream使用可选的功能模式,您可以阅读更多blog post

3
投票
回答问题:可能。

1
投票
[您可以采用(Java *)方法来编写一个几乎为空的Stream类,该类继承基MyStream类,但提供了大多数成员方法(例如Stream)并使用合理的默认值来嵌入它们行为(例如,抛出CanSeek())。然后,您的真实类只需扩展您的NotImplemented类,即可实现您真正需要的另外两个或三个方法。

0
投票
我的流类问题是Length属性-它没有指定如何实现未知长度,未指定长度或无限长度的流!

0
投票
我认为MyStream类的设计很差,因为它实际上违反了单一职责原则。我认为阅读与写作完全不同。但是Stream类允许读取和写入同一流。而且,如果我们真的想到了一个真正的流,那么我们几乎无法想象如何寻找一个流。实际上,您可以跳过流中的某些字节,但不能后退(特别是在写入时)。想象一下,一股流淌着血红色液体的水流。流中的红色液体流入或流出-根据流动的方向而产生或消耗。无法同时在两个方向上查看流。试图一次在两个方向上查看都会导致从.NET已知的Stream类。更清楚地说-封装一个破坏SRP的类会产生更多的代码味道。只需在Stream方法中查看BufferedStream类源代码。
© www.soinside.com 2019 - 2024. All rights reserved.