C++ 这是一个糟糕的设计吗?
C++ 这是一个糟糕的设计吗?,c++,oop,design-patterns,C++,Oop,Design Patterns,columndMetadata是一个从包含这三个类的信息的表数据库中检索的类(IStreamMetadata,IFileMetadata,ISocketMetadata) 编译器给了我一个警告 class IStreamMetadata{ public: virtual DataStreamType getType() = 0; virtual int getMaxFieldSize() = 0; virtual SourceType getSourceType() =
columndMetadata
是一个从包含这三个类的信息的表数据库中检索的类(IStreamMetadata
,IFileMetadata
,ISocketMetadata
)
编译器给了我一个警告
class IStreamMetadata{
public:
virtual DataStreamType getType() = 0;
virtual int getMaxFieldSize() = 0;
virtual SourceType getSourceType() = 0;
virtual void setType(DataStreamType dsType) = 0;
virtual void setSourceType(SourceType )= 0;
virtual void setMaxFieldSize(int size) = 0;
};
class IFileMetadata: public IStreamMetadata{
public:
virtual string getPath() = 0;
virtual void setPath(string path) = 0;
};
class ISocketMetadata: public IStreamMetadata{
public:
virtual int getPort() = 0;
};
class ColumnDBMetadata: public IStreamMetadata, public IFileMetadata, public ISocketMetadata
在
columndMetadata
内部创建方法是否更好,比如getStreamMetadata
,getFileMetadata
,getSocketMetadata
。或者将ColumnDBMetadata
传递给创建正确接口的工厂?有一种气味。。。列如何实现流、文件和套接字?看起来,它可能是这些类的消费者,但不是天生的
混淆了,你的基本流<代码>接口<代码>(我明白它是C++的一个接口而不是真正的一个接口!),它没有公开足够的通用功能来帮助它。文件和套接字接口实现不同的语义。您需要一个更通用的接口,该接口由文件/套接字实现,然后只需将基本接口传递给
columndMetadata
的构造函数,它就可以随心所欲地使用它,因为您已经混淆了实现
也可以考虑将此添加到基本接口类:
C4584: 'ColumnDBMetadata' : base-class 'IStreamMetadata' is already a base-class of 'IFileMetadata'.
是的,这是个糟糕的设计。大多数人都会理解这个
类ColumnDBMetadata:public IStreamMetadata、public IFileMetadata、public ISocketMetadata
意味着ColumnDBMetadata
的实例是所有3个实例同时出现
如果您想摆脱所有继承,那么拥有getStreamMetadata、getFileMetadata、getSocketMetadata
的想法是可以的
另一种方法是反转您提出的层次结构:使DB类基类接口,并让套接字、流和文件元数据继承它。因此,您将首先创建DB类(通过工厂),确定它是什么,然后将其向下转换为一种特殊类型。我不打算评论语义。只要您从中继承的所有类都是纯虚拟的(这是C++拥有接口的方式),这种设计的形状就应该很好。然而,你犯了一个错误 您的继承应该如下所示:
virtual ~IStreamMetaData() = 0 { };
virtual关键字的作用是将所有重复继承的函数定义融合在一起。如果您不这样做,编译器会认为您继承了同名的不同函数,这就是您收到该警告的原因
基本上,您应该养成一种习惯,始终将纯虚拟的“接口”类继承为
公共虚拟机
此外,您还需要在所有这些接口类中编写一个空的内联虚拟析构函数,因为即使该类不做任何事情,该语言也希望有一个虚拟析构函数
请记住,这种设计很好,因为您只有纯虚拟方法,没有其他方法。如果要在任何继承的类中添加字段或单个实现的函数(除析构函数外),这将是适当的多重继承,如果愿意,最好先花大量时间搜索主题。我发现包含“数据”、“信息”、“管理器”的类很奇怪,以及类似的后缀。流需要的所有数据(理论上)都包含(甚至可能隐藏)在类中。每次我想上这样的课时,我都会问自己:我为什么要这样做?一定还有别的办法。在不知道这些类的上下文的情况下,这将是我改进设计的一个问题
然后定义许多getter。我并不是说获得者一般都是邪恶的。在SO(搜索getter和setter)上有一些关于这个主题的很好的讨论。对我来说,getters再次暗示,有些事情可以做得更好。一个能干的人说:我不知道怎么做,所以在这里拿东西,自己做。有时我会接受这种情况,有时我会为此找到更好的设计。查阅diamond Inheritation,你会很快找到一些缺失的好解释。首先,确保你问自己“是a”或“有a”。另外,我会避免使用以
I
开头的类。使它看起来像一个接口
。如果文件
是一个流
,那么将这两个文件都保存有什么意义呢?@crashmstr:这是一个接口。我忘记了实现析构函数,这看起来像java,不是C++。有很多能手和能手,还有深厚的继承力。如果你不是在寻找多态性,为什么要用它来代替模板呢?单个setter真的有用吗,还是应该改为构造函数参数?或者我们正在查看原始数据存储(在这种情况下,您应该使用struct
,直接访问元素,而不是通过函数调用)?该列只包含有关这些接口的信息。columnDBMetadata只是一个检索信息的对象。从数据库中,我想说的是,它可能会使用各种流,但不会继承,因为它本身不是流。请看Crashstr关于“是a”和“有a”的评论。我忘记了做这件事,就像我上面提到的那样。
class IFileMetadata: public virtual StreamMetadata
class ISocketMetadata: public virtual IStreamMetadata
class ColumnDBMetadata: public virtual IStreamMetadata, public virtual IFileMetadata, public virtual ISocketMetadata