Oop 依赖、关联或组合哪个类设计更合适

Oop 依赖、关联或组合哪个类设计更合适,oop,design-patterns,uml,class-design,Oop,Design Patterns,Uml,Class Design,我有三种可能的设计,我试图确定哪一种更好,在哪种情况下会更好。所有设计的总体思路是,有一个数据对象存储一些数据,还有一个analyzer对象分析数据 我需要在这些设计中进行选择,我最喜欢设计2。然而,一位与我合作的开发人员正在推动设计3,我认为这是最糟糕的。这些设计有什么优点或缺点是我没有的吗?如果需要澄清,请告诉我 设计1 在设计1中,DataAnalyzer有一个在构造期间提供的数据对象。当客户端调用dataAnalyzer.analyze()时,将分析数据。在本次设计中,各对象责任明确;

我有三种可能的设计,我试图确定哪一种更好,在哪种情况下会更好。所有设计的总体思路是,有一个数据对象存储一些数据,还有一个analyzer对象分析数据

我需要在这些设计中进行选择,我最喜欢设计2。然而,一位与我合作的开发人员正在推动设计3,我认为这是最糟糕的。这些设计有什么优点或缺点是我没有的吗?如果需要澄清,请告诉我

设计1

在设计1中,DataAnalyzer有一个在构造期间提供的数据对象。当客户端调用
dataAnalyzer.analyze()
时,将分析数据。在本次设计中,各对象责任明确;数据对象只是保存数据,DataAnalyzer对象分析数据。更改存储的数据只会更改数据类,添加分析方法类型只会更改DataAnalyzer类。这种设计的一个问题是DataAnalyzer对象只能用于构造期间传入的数据对象,因此如果有很多数据对象,则需要创建很多DataAnalyzer。另一个缺点(从设计3中可以更清楚地看到)是客户机需要了解两个类,而不是一个。如果有更多的类与数据关联,客户机将不得不处理所有这些类

设计2

设计2与设计1非常相似,只是现在DataAnalyzer可重用(用于不同的数据对象)。客户端仍然必须使用两个类,而不是设计3中的一个类。责任仍然很明确,维护也很容易

设计3


设计3允许客户端使用一个对象。客户端可以说
data.analyze()
,但对DataAnalyzer一无所知。我不确定这是否违反了单一责任规则;数据对象有一个允许分析的接口,但责任实际上是委托给DataAnalyzer的。另一个问题是,无论是否需要分析数据,都会为创建的每个数据对象创建一个DataAnalyzer。现在如果增加更多的功能,很多事情都会改变。如果创建了DataPrinter类(假设这比让数据打印数据本身要好),客户端就不必担心创建DataPrinter对象并调用
DataPrinter.printData()
,只需调用
data.print()
。然而,通过添加这个类,我不得不更改数据接口。将更多方法添加到任何DataXX类都会导致将方法添加到数据类。

Design 3不是很理想,因为数据分析器必须始终存在。我相信在很多情况下,您并不总是需要将该类附加到DO。此外,我同意它违反了单一责任原则

如果不同数据对象类型的内部机制/方法不同,设计2可能会出现一些问题。每次都必须重新初始化它。我认为这也违反了单一责任原则。数据分析器应该只需要考虑一种类型的数据对象。它不必在每次新数据对象进入时都重置和重做其内部工作


设计1是三个设计中我最喜欢的,但不是我理想的设计。理想情况下,我会将数据对象传递给Analyzer工厂。工厂为特定的数据对象生成一个分析器,然后分析器就可以完成它的工作了。这可能是最容易维护的解决方案。

设计3不是很理想,因为数据分析器必须始终在那里。我相信在很多情况下,您并不总是需要将该类附加到DO。此外,我同意它违反了单一责任原则

如果不同数据对象类型的内部机制/方法不同,设计2可能会出现一些问题。每次都必须重新初始化它。我认为这也违反了单一责任原则。数据分析器应该只需要考虑一种类型的数据对象。它不必在每次新数据对象进入时都重置和重做其内部工作


设计1是三个设计中我最喜欢的,但不是我理想的设计。理想情况下,我会将数据对象传递给Analyzer工厂。工厂为特定的数据对象生成一个分析器,然后分析器就可以完成它的工作了。这可能是最易于维护的解决方案。

如果分析需要很长时间或大量资源,并且您可以使用某种缓存使相同数据上的顺序分析运行得更快(或资源更少),则Design 1非常有用。
-如果需要存储中间结果或缓存每个正在分析的数据实例的最终结果,请使用此选项

Design 2如果您想要一个静态、线程安全的分析器,它可以为不同的数据反复调用,并且不需要资源来完成,或者可以从资源池中获得每个请求的不同资源,那么它非常有用

如果您有不同的数据类型(具有相同的基类或接口),那么可以使用访问者模式、依赖项注入、反射或命令模式从主类到达正确的具体数据分析器类,从而不违反单一责任原则

设计3是一个坏主意,因为这意味着您正在将数据类型与对其进行的处理进行耦合-每次您想要添加或更改处理时,如果您决定使用此设计,您将诅咒您的决定:-)


在某些语言中,例如在C#3.0+中,有一种方法可以使用Design 3的语法使Design 2的操作正常工作。

Design 1非常有用
................................
....+----------------------+....
....|      CPPParser       |....
....+----------------------+....
....| [+] CPPStream Source |....
....+----------+-----------+....
...............|................
...............|................
...............v................
....+----------+-----------+....
....|     <<abstract>>     |....
....|       CPPStream      |....
....+----------------------+....
................................
............................................................
....+----------------------+................................
....|      CPPStream       |................................
....+----------------------+................................
....| [+] CPPStream Source |................................
....+----------+-----------+................................
...............^............................................
...............|............................................
...............|............................................
...............+---------------------------+................
...............|...........................|................
...............|...........................|................
...............|...........................|................
....+----------+-----------+....+----------+-------------+....
....|     <<concrete>>     |....|      <<concrete>>      |....
....|    CPPFileStream     |....|     CPPFileStream      |....
....+----------------------+....+------------------------+....
....| [+] String Filename  |....| [+] String StringValue |....
....+----------------------+....+------------------------+....
............................................................