Questions tagged «solid»

一组设计原则的助记符:单项责任,开放式,封闭式,Liskov替代,接口隔离,依赖性反转

8
不代表任何内容的类-是否正确?
我只是在设计应用程序,不确定我是否正确理解SOLID和OOP。类应该做一件事情并且做得很好,但另一方面,它们应该代表我们所使用的真实对象。 就我而言,我对数据集进行特征提取,然后进行机器学习分析。我假设我可以创建三个类 FeatureExtractor 数据集 分析仪 但是FeatureExtractor类不代表任何东西,它的作用使它比类更像是一个例程。它只有一个将要使用的函数:extract_features() 创建不代表一件事而是做一件事的类是否正确? 编辑:不确定是否重要,但我正在使用Python 并且如果extract_features()看起来像这样:是否值得创建一个特殊的类来保存该方法? def extract_features(df): extr = PhrasesExtractor() extr.build_vocabulary(df["Text"].tolist()) sent = SentimentAnalyser() sent.load() df = add_features(df, extr.features) df = mark_features(df, extr.extract_features) df = drop_infrequent_features(df) df = another_processing1(df) df = another_processing2(df) df = another_processing3(df) df = set_sentiment(df, sent.get_sentiment) return df

8
一个班级的真正责任是什么?
我一直想知道在OOP中使用基于名词的动词是否合法。 我遇到了这篇精彩的文章,尽管我仍然不同意它的观点。 为了进一步解释该问题,文章指出,例如,不应有一个FileWriter类,但是由于编写是一种动作,因此它应该是该类的方法File。您将认识到它通常与语言相关,因为Ruby程序员可能会反对使用FileWriter类(Ruby使用方法File.open来访问文件),而Java程序员则不会。 我个人的观点(是的,非常谦虚)是,这样做会违反“单一责任”原则。当我用PHP编程时(因为PHP显然是OOP的最佳语言,对吗?),我经常会使用这种框架: <?php // This is just an example that I just made on the fly, may contain errors class User extends Record { protected $name; public function __construct($name) { $this->name = $name; } } class UserDataHandler extends DataHandler /* knows the pdo object */ { public function …

5
依赖倒置与高阶函数有何关系?
今天我刚刚看到这篇文章,它描述了SOLID原理在F#开发中的相关性- F#和设计原则– SOLID 在谈到最后一个问题时-“依赖倒置原则”,作者说: 从功能的角度来看,这些容器和注入概念可以通过简单的高阶函数或内置在语言中的“中间钻孔”模式来解决。 但是他没有进一步解释。因此,我的问题是,依赖项反转与高阶函数有何关系?

11
确保每个班级只有一个责任,为什么?
根据Microsoft文档,有关Wikipedia SOLID原则的文章或大多数IT架构师,我们必须确保每个班级仅负一个责任。我想知道为什么,因为如果每个人似乎都同意这条规则,那么似乎没人会同意这条规则的原因。 一些人引用了更好的维护,有人说它提供了简单的测试,或者使类更加健壮或安全。什么是正确的,实际上是什么意思?为什么它可以使维护更好,测试更容易或代码更健壮?


5
您应该在哪里放置常数,为什么?
在大多数大型应用程序中,通常只有几个“常量”位置: 一类用于GUI和内部内容的内容(制表页标题,组框标题,计算因子,枚举) 一类用于数据库表和列(此部分是生成的代码)以及它们的可读名称(手动分配) 一类应用程序消息(日志,消息框等) 在这些类中,常量通常分为不同的结构。在我们的C ++应用程序中,仅在.h文件中定义常量,而在.cpp文件中分配值。 优点之一是,所有琴弦等都放在一个中央位置,每个人都知道在必须更改某些内容时可以在哪里找到它们。 这尤其是项目经理在人们来来往往时喜欢的东西,这样每个人都可以更改这些琐碎的事情,而不必深入研究应用程序的结构。 另外,您可以轻松地一次更改相似的“组框” /“选项卡页”等的标题。另一个方面是,您可以仅打印该类并将其交给非程序员,该非程序员可以检查字幕是否直观,向用户发送的消息是否太详细或太混乱等。 但是,我看到了某些缺点: 每个类都与常量类紧密耦合 添加/删除/重命名/移动常量需要重新编译至少90%的应用程序(注意:至少在C ++中,不需要更改值)。在我们的一个带有1500个类的C ++项目中,这意味着大约7分钟的编译时间(使用预编译的标头;如果没有它们,则大约为50分钟),再加上大约10分钟的链接到某些静态库。 通过Visual Studio编译器构建速度优化的发行版最多需要3个小时。我不知道是否大量的类关系是源,但也有可能。 您会被迫将临时硬编码的字符串直接转化为代码,因为您想非常快速地测试某项内容,并且不想仅等待15分钟来进行该测试(并且可能以后每次测试)。每个人都知道“以后我会解决”的想法。 在另一个项目中重用一个类并不总是那么容易(主要是由于其他紧密的耦合,但是常量处理并没有使它更容易。) 您将在哪里存储这样的常量?为了使您的项目经理相信还有更好的概念也符合上面列出的优点,您还会提出什么论点? 随意给出特定于C ++或独立的答案。 PS:我知道这个问题是主观的,但是老实说,我不知道有比这个网站更好的地方。 有关此项目的更新 关于编译时间,我有个新闻: 在Caleb和gbjbaanb的帖子中,有空时,我将常量文件拆分为其他几个文件。我最终还将我的项目分成几个库,现在可以轻松得多。在发布模式下进行编译显示,包含数据库定义(表,列名等-超过8000个符号)并建立了某些哈希值的自动生成的文件在发布模式下造成了巨大的编译时间。 现在,通过停用包含DB常量的库的MSVC优化器,我们可以将发布模式下的项目(几个应用程序)的总编译时间从最多8小时减少到不到一小时! 我们还没有找到为什么MSVC很难优化这些文件,但是现在,由于我们不再只依赖夜间构建,因此此更改减轻了很多压力。 这个事实以及其他好处,例如紧密耦合少,可重用性更好等,也表明花时间拆分“常量”并不是一个坏主意;-) 更新2 由于这个问题仍然受到关注: 这是过去几年中我一直在做的事情: 将每个常量,变量等完全放在与其相关的范围内:如果仅在单个方法中使用常量,则可以在该方法中定义它。如果单个类对此感兴趣,请将其保留为该类的私有实现细节。这同样适用于名称空间,模块,项目,公司范围。我还将相同的模式用于助手功能等。(如果您开发一个公共框架,这可能不会100%适用。) 这样做可以提高可重用性,可测试性和可维护性,使您不仅花费更少的时间(至少在C ++中),而且花费在错误修复上的时间也更少,这使您有更多的时间实际开发新功能。同时,开发这些功能的速度会更快,因为您可以更轻松地重用更多代码。这在一定程度上胜过中央常量文件可能具有的任何优势。 如果您想了解更多,请特别看一下接口隔离原则和单一职责原则。 如果您同意,请支持Caleb的回答,因为此更新基本上是他所说的更一般的看法。

6
块中的附加行与清理代码中的附加参数
语境 在第35页的“ 清理代码”中,它说 这意味着if语句,else语句,while语句等中的块应为一行。该行可能是函数调用。这不仅使封闭函数较小,而且还增加了文档价值,因为在块中调用的函数可以具有很好的描述性名称。 我完全同意,这很有意义。 稍后,在第40页上,它介绍了有关函数参数的信息 函数的理想参数个数为零(尼拉度)。接下来是一个(单声道),紧接着是两个(双声道)。在可能的情况下,应避免使用三个参数(三重性)。超过三个(多义词)需要非常特殊的理由-因此无论如何都不应使用。争论很难。他们具有很大的概念力。 我完全同意,这很有意义。 问题 但是,通常我会发现自己从另一个列表创建了一个列表,而我将不得不忍受两个弊端之一。 我在代码块中使用了两行,一行用于创建事物,一行用于将其添加到结果中: public List<Flurp> CreateFlurps(List<BadaBoom> badaBooms) { List<Flurp> flurps = new List<Flurp>(); foreach (BadaBoom badaBoom in badaBooms) { Flurp flurp = CreateFlurp(badaBoom); flurps.Add(flurp); } return flurps; } 或者,我在要向其中添加事物的列表的函数中添加了一个参数,从而使其“变差了一个参数”。 public List<Flurp> CreateFlurps(List<BadaBoom> badaBooms) { List<Flurp> flurps = new List<Flurp>(); foreach (BadaBoom badaBoom …
33 clean-code  solid 

9
设计一个类以将整个类作为参数而不是单个属性
举例来说,假设您有一个应用程序,该应用程序具有广泛共享的类,称为User。此类公开有关用户,其ID,名称,对每个模块的访问级别,时区等所有信息。 用户数据显然在整个系统中得到了广泛的引用,但是无论出于何种原因,都对系统进行了设置,因此,我们不是在将用户对象传递到依赖于该对象的类中,而是从其中传递了各个属性。 需要用户ID的类仅需要GUID userId作为参数,有时我们可能还需要用户名,因此将其作为单独的参数传递。在某些情况下,这将传递给各个方法,因此这些值根本不会保存在类级别。 每当我需要从User类访问不同的信息时,我都必须通过添加参数进行更改,而在不适合添加新的重载的地方,我也必须更改对方法或类构造函数的每个引用。 用户只是一个例子。这在我们的代码中得到了广泛的实践。 我认为这违反了开放/封闭原则,对吗?不仅是更改现有类的行为,而且是首先设置它们,以便将来很有可能需要进行广泛的更改吗? 如果我们只是传入User对象,则可以对正在使用的类进行一些小的更改。如果必须添加参数,则可能不得不对类的引用进行数十次更改。 这种做法是否违反了其他任何原则?依赖倒置也许?尽管我们没有引用抽象,但是只有一种类型的用户,因此并没有真正需要User界面的需求。 是否还有其他违反非Solid的原则,例如基本的防御性编程原则? 我的构造函数应如下所示: MyConstructor(GUID userid, String username) 或这个: MyConstructor(User theUser) 发表编辑: 已经建议在“密码或对象?”中回答问题。这并未回答以下问题的问题:无论哪种方式的决定都会如何影响遵循SOLID原则的尝试,而SOLID原则是此问题的核心。
30 java  c#  design  solid 




12
SOLID与避免过早抽象
我了解SOLID在模块化很重要且其目标显然有用的情况下应定期完成并使用的功能。但是,有两点使我无法在代码库中一致地应用它: 我想避免过早的抽象。以我的经验,绘制没有具体用例(现在或可预见的将来)的抽象线会导致将它们绘制在错误的位置。当我尝试修改此类代码时,抽象行会妨碍您的工作,而不是有所帮助。因此,我倾向于不画任何抽象线,直到我对它们的用处有了一个很好的认识。 我发现很难证明增加模块化本身是合理的,如果它使我的代码更冗长,更难理解等,并且不能消除任何重复。我发现有时,简单,紧密耦合的过程或God对象代码比构造良好的馄饨代码更易于理解,因为流程简单且线性。编写起来也容易得多。 另一方面,这种心态常常导致神的对象。我通常会保守地重构它们,仅在看到清晰的模式出现时才添加清晰的抽象线条。如果您显然不需要更多的模块化,没有大量重复且代码可读性强,那么上帝对象和紧密耦合的代码怎么办? 编辑:就个别SOLID原则而言,我想强调的是,Liskov Substitution是IMHO的常识形式化,应在所有地方应用,因为如果不是这样的话,抽象是没有意义的。同样,每个类都应该在某个抽象级别上担负单个责任,尽管这可能是一个很高的级别,将实现细节都塞进一个庞大的2,000行类中。基本上,您的抽象应该在您选择抽象的地方有意义。在模块化不是很有用的情况下,我所质疑的原则是开放式,接口隔离,尤其是依赖关系倒置,因为这些都是关于模块化的,而不仅仅是让抽象有意义。

8
是否有某些SOLID原则与清洁代码相反的OOP风格?
我最近与我的一个朋友讨论了有关视频游戏开发中OOP的问题。 我正在解释我的一款游戏的体系结构,令我的朋友惊讶的是,它包含许多小类和几个抽象层。我认为这是我专注于赋予一切单一职责并放松组件之间的耦合的结果。 他担心的是,大量的课程将转化为维护的噩梦。我的看法是,它将产生完全相反的效果。我们进行了长达数个世纪的讨论,最终同意了不同意,说也许在某些情况下SOLID原则和适当的OOP实际上并不能很好地融合在一起。 甚至Wikipedia关于SOLID原则的条目都指出,它们是有助于编写可维护代码的指南,并且它们是敏捷和自适应编程的整体策略的一部分。 所以,我的问题是: 在OOP中是否存在某些或全部SOLID原则不适合清理代码的情况? 我可以马上想象一下,《李斯科夫替代原则》可能与另一种安全继承形式发生冲突。也就是说,如果有人设计了通过继承实现的另一种有用模式,则LSP很可能与其直接冲突。 还有其他吗?也许某些类型的项目或某些目标平台可以使用较少的SOLID方法更好地工作? 编辑: 我只想说明我不是在问如何改善代码;)我在这个问题中提到一个项目的唯一原因是提供一些上下文。我的问题是关于OOP和一般的设计原则。 如果您对我的项目感到好奇,请参阅this。 编辑2: 我以为可以用以下三种方式之一回答这个问题: 是的,存在与SOLID部分冲突的OOP设计原则 是的,存在与SOLID完全冲突的OOP设计原则 不,SOLID是蜜蜂的膝盖,OOP将永远更好。但是,与所有内容一样,它不是万能药。负责任地喝酒。 选项1和2可能会产生很长且有趣的答案。另一方面,选项3是一个简短的,无趣的,但总体上令人放心的答案。 我们似乎正在选择方案3。

11
在Bank world中选择代码设计工作或懒惰
我在一家出色的投资银行工作了两年。 我进行了一些技术项目,希望创建最优化的代码,同时尊重适应的良好设计模式,SOLID原则,demeter规律并避免各种重复的代码... 当生产交付=>零错误时,一切都按预期进行。 但是,大多数开发人员来找我是为了使我的所有代码过于复杂以至于无法理解阅读。我听了一个例子:“做一些if和instanceof,忘记多态性,这样很容易纠正紧急生产错误”。我不想回答…… 知道这些开发人员一点也不好奇,拒绝努力理解一个好的设计(例如,90%的开发人员不知道什么是策略模式,并且编写过程代码,并且从不进行设计,因为他们说,他们很简单) ),我的项目经理告诉我,我对银行世界的看法确实是错误的,而且过于理想化。 你会建议我什么?我要重申的是,我是否真的希望真正好的代码,或者让我适应大多数开发人员,对于我来说,重复设计代码对我而言,这并不是真正有趣的设计代码,而是我们开发人员工作的全部美。 或者相反,他们是否应该学习基本的面向对象原则和最佳实践以适应我的代码?

5
具有后备情况的特殊情况是否违反《里斯科夫替代原则》?
假设我有一个FooInterface具有以下签名的接口: interface FooInterface { public function doSomething(SomethingInterface something); } 还有一个ConcreteFoo实现该接口的具体类: class ConcreteFoo implements FooInterface { public function doSomething(SomethingInterface something) { } } ConcreteFoo::doSomething()如果它传递了一种特殊类型的SomethingInterface对象(例如称为SpecialSomething),我想做一些独特的事情。 如果我加强方法的先决条件或引发新的异常,则绝对是LSP违规,但是如果我SpecialSomething在为通用SomethingInterface对象提供后备时又对特殊情况的对象进行了处理,这是否仍会违反LSP ?就像是: class ConcreteFoo implements FooInterface { public function doSomething(SomethingInterface something) { if (something instanceof SpecialSomething) { // Do SpecialSomething magic } else { // Do generic …

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.