Questions tagged «object-oriented-design»

面向对象的设计是规划用于解决软件问题的交互对象系统的过程。

3
如何解决循环依赖?
我有三个相互循环依赖的类: TestExecuter执行TestScenario的请求,并使用ReportGenerator类保存报告文件。所以: TestExecuter依赖ReportGenerator生成报告 ReportGenerator取决于TestScenario和TestExecuter设置的参数。 TestScenario取决于TestExecuter。 无法弄清楚如何删除那些依赖项。 public class TestExecuter { ReportGenerator reportGenerator; public void getReportGenerator() { reportGenerator = ReportGenerator.getInstance(); reportGenerator.setParams(this.params); /* this.params several parameters from TestExecuter class example this.owner */ } public void setTestScenario (TestScenario ts) { reportGenerator.setTestScenario(ts); } public void saveReport() { reportGenerator.saveReport(); } public void executeRequest() { /* …

2
如何设计可扩展的通知系统?[关闭]
我需要写一个通知系统管理员。 这是我的要求: 我需要能够在可能完全不同的不同平台上发送通知(例如,我需要能够发送SMS或电子邮件)。 有时,对于给定平台的所有收件人,通知可能是相同的,但是有时,可能是每个平台(或多个)每个收件人的通知。 每个通知可以包含特定于平台的有效负载(例如,MMS可以包含声音或图像)。 系统需要可伸缩,我需要能够发送大量通知而不会导致应用程序或服务器崩溃。 这是一个分为两个步骤的过程,首先,客户可以输入消息并选择要发送到的平台,然后创建通知,以便稍后进行实时处理。 然后,系统需要将通知发送到平台提供商。 就目前而言,尽管我得到了一些结论,但是我不知道它的可扩展性或它是否是一个好的设计。 我有以下对象(使用伪语言): 通用Notification对象: class Notification { String $message; Payload $payload; Collection<Recipient> $recipients; } 如果我有1.000.000收件人,则以下对象的问题是什么?即使Recipient对象很小,也会占用太多内存。 我还可以为每个收件人创建一个通知,但是某些平台提供商要求我批量发送该通知,这意味着我需要定义一个包含多个收件人的通知。 每个创建的通知可以存储在诸如DB或Redis的持久性存储中。 稍后汇总此内容以确保其可伸缩性是否很好? 在第二步中,我需要处理此通知。 但是,如何区分通知给正确的平台提供商的通知呢? 我应该使用诸如MMSNotification扩展对象之类的对象abstract Notification吗?或类似的东西Notification.setType('MMS')? 为了允许同时处理大量通知,我认为像RabbitMQ这样的消息传递队列系统可能是正确的工具。是吗? 这将使我可以排队很多通知,并有几个工作人员弹出通知并进行处理。但是,如果我需要如上所述对收件人进行批处理怎么办? 然后我想象NotificationProcessor的,我我可以添加对象NotificationHandler的每个NotificationHandler将负责连接平台提供商和执行通知。 我也可以使用EventManager允许插入行为。 有任何意见或建议吗? 感谢您抽出宝贵的时间。 注意:我曾经使用过PHP,并且它可能是我选择的语言。 编辑 (根据morphunreal的答案) 您每秒发送多少消息(定义当前/初始级别,定义在重新设计之前系统应处理的最大级别) 系统具有哪些硬件限制(内存,CPU等可供系统使用) 硬件将如何扩展(即添加更多服务器,云计算等) 哪些语言/系统将生成通知? 它是我自己的事情,我负责以编程方式创建通知,但该通知是通过用户界面构建的。 生成器是否知道消息的收件人(?),还是通过其他某种方式提供消息(例如,某些警报类型的业务规则将发送给某些收件人) 应该可以为特定收件人,一组收件人(例如,使用标签系统)或整个平台创建通知。 是否有添加CC / BCC /阅读收据的业务规则 是。请注意,这实际上是特定于平台的,read或cc并非在所有平台上都可用。 …

7
在循环中设置标记以供以后使用是否有代码味道?
我有一段代码在其中迭代地图,直到某个条件为真,然后再使用该条件做更多的事情。 例: Map<BigInteger, List<String>> map = handler.getMap(); if(map != null && !map.isEmpty()) { for (Map.Entry<BigInteger, List<String>> entry : map.entrySet()) { fillUpList(); if(list.size() > limit) { limitFlag = true; break; } } } else { logger.info("\n>>>>> \n\t 6.1 NO entries to iterate over (for given FC and target) \n"); } if(!limitFlag) …

3
“开始”,“运行”或“执行”方法是一种好习惯吗?
我目前正在开发具有许多实现Start方法的类的代码库。在我看来,这似乎是两阶段构建,我一直认为这是一种不良做法。我不能说这和构造函数之间的区别。 什么时候适合使用start方法而不是普通的对象构造方法? 我何时应该更喜欢使用构造函数? 编辑:我不认为这是相关的,但是编程语言是C#,它同样适用于Java或C ++

10
函数式编程支持者将如何在Code Complete中回答此声明?
在第二版的839页上,史蒂夫·麦康奈尔(Steve McConnell)讨论了程序员在大型程序中“克服复杂性”的所有方式。他的提示最终体现在: “面向对象的编程提供了同时适用于算法和数据的抽象级别,这是仅功能分解无法提供的那种抽象。” 加上他的结论“降低复杂度可以说是成为有效程序员的最重要的关键”(同一页),这似乎对函数式编程构成了很大的挑战。 FP和OO之间的辩论通常由FP支持者围绕复杂性问题进行,这些复杂性问题特别来自于并发或并行化的挑战。但是并发当然不是程序员必须克服的唯一复杂性。也许专注于减少一种复杂性会在其他方面大大增加它的复杂度,以至于在许多情况下,增加收益是不值得的。 如果我们将FP和OO之间的比较术语从并发性或可重用性等特定问题转移到全局复杂性的管理上,那场辩论会如何? 编辑 我想强调的对比是,OO似乎封装和抽象了数据和算法的复杂性,而函数式编程似乎鼓励在整个程序中使数据结构的实现细节更加“暴露”。 例如,参见Stuart Halloway(Clojure FP的支持者)在这里说,“数据类型的过度规范”是“惯用的OO风格的负面结果”,并主张将AddressBook概念化为简单的矢量或映射而不是更丰富的OO对象。以及其他(非向量化和非地图类)属性和方法。(此外,OO和领域驱动设计的支持者可能会说,将地址簿公开为向量或映射会使封装的数据过度暴露于从域的角度来看无关紧要甚至危险的方法)。

17
通过抽象隐藏细节有什么价值?透明度没有价值吗?
背景 我不是抽象的忠实粉丝。我会承认,人们可以从接口的适应性,可移植性和可重用性中受益。那里确实有好处,我不想质疑这一点,所以让我们忽略它。 抽象还有另一个主要的“好处”,即向该抽象的用户隐藏实现逻辑和细节。论据是您不需要了解细节,并且此时人们应该专注于自己的逻辑。从理论上讲是有道理的。 但是,无论何时维护大型企业应用程序,我总是需要了解更多细节。只是为了确切地找出某物在做什么,就变得越来越麻烦,它不断地深入研究抽象。也就是说,在找到所使用的存储过程之前,必须执行“打开声明”大约12次。 这种“隐藏细节”的心态似乎只是阻碍。我一直希望界面更透明,抽象更少。我可以阅读高级源代码并知道它的作用,但是我永远不知道它是如何执行的,何时执行的,是我真正需要知道的。 这里发生了什么?我曾经使用过的每个系统是否都经过了错误的设计(至少从这个角度而言)? 我的理念 当我开发软件时,我觉得我尝试遵循一种与ArchLinux哲学密切相关的哲学: Arch Linux保留了GNU / Linux系统固有的复杂性,同时使它们井井有条,透明。Arch Linux开发人员和用户认为,试图隐藏系统的复杂性实际上会导致系统更加复杂,因此应避免使用。 因此,我从未尝试将软件的复杂性隐藏在抽象层的后面。我试图滥用抽象,而不是成为抽象的奴隶。 心中的问题 隐藏细节有真正的价值吗? 我们不是在牺牲透明度吗? 这种透明度难道不有价值吗?

10
抽象类上的接口
我和我的同事对基类和接口之间的关系有不同的看法。我相信一个类不应实现接口,除非在需要实现接口时可以使用该类。换句话说,我喜欢看这样的代码: interface IFooWorker { void Work(); } abstract class BaseWorker { ... base class behaviors ... public abstract void Work() { } protected string CleanData(string data) { ... } } class DbWorker : BaseWorker, IFooWorker { public void Work() { Repository.AddCleanData(base.CleanData(UI.GetDirtyData())); } } DbWorker是获得IFooWorker接口的对象,因为它是该接口的可实例化实现。它完全履行了合同。我的同事更喜欢几乎相同的东西: interface IFooWorker { void Work(); } …

3
在TDD中重新设计后该方法变为私有后,方法的测试会如何?
假设我开始开发角色扮演游戏,角色扮演者会攻击其他角色以及类似的东西。 应用TDD,我做了一些测试用例来测试Character.receiveAttack(Int)方法内部的逻辑。像这样: @Test fun healthIsReducedWhenCharacterIsAttacked() { val c = Character(100) //arg is the health c.receiveAttack(50) //arg is the suffered attack damage assertThat(c.health, is(50)); } 说我有10种方法测试receiveAttack方法。现在,我添加一个方法Character.attack(Character)(调用receiveAttackmethod),并在经过一些TDD循环测试之后,我做出一个决定:Character.receiveAttack(Int)应该是private。 前10个测试用例会发生什么?我应该删除它们吗?我应该保留方法public(我不这样认为)吗? 这个问题不是关于如何测试私有方法的,而是关于在应用TDD时重新设计后如何处理它们的问题。

4
C#6.0的新空条件运算符是否违反Demeter定律?
该德米特法律规定如下: 每个单元对其他单元的知识应该有限:只有与当前单元“紧密”相关的单元。 每个单位只能与朋友交谈;不要和陌生人说话。 只与您的直系朋友交谈。 C#6.0引入了一个称为空条件运算符的新运算符。恕我直言,它使编码更容易并提高了可读性。但这也使编写更多耦合的代码变得更容易,因为更容易在已经检查了无效性的类字段中导航(类似var x = A?.B?.C?.D?.E?.F?)。 陈述这名新操作员违反Demeter法则是否正确?

6
您可以在没有class关键字的情况下实现“面向对象”编程吗?
假设我们要提供银行“帐户”的抽象。这是function在Python中使用对象的一种方法: def account(): """Return a dispatch dictionary representing a bank account. >>> a = account() >>> a['deposit'](100) 100 >>> a['withdraw'](90) 10 >>> a['withdraw'](90) 'Insufficient funds' >>> a['balance'] 10 """ def withdraw(amount): if amount > dispatch['balance']: return 'Insufficient funds' dispatch['balance'] -= amount return dispatch['balance'] def deposit(amount): dispatch['balance'] += amount return dispatch['balance'] …

6
是否有一种设计模式可以消除检查标志的需要?
我将在数据库中保存一些字符串有效负载。我有两个全局配置: 加密 压缩 可以使用配置启用或禁用这些功能,方法是仅启用其中一个,两个都启用或两个都禁用。 我当前的实现是这样的: if (encryptionEnable && !compressEnable) { encrypt(data); } else if (!encryptionEnable && compressEnable) { compress(data); } else if (encryptionEnable && compressEnable) { encrypt(compress(data)); } else { data; } 我在考虑装饰器模式。是正确的选择,还是有更好的选择?

7
函数式编程是否忽略了“关于将系统分解为模块所用的准则”(数据隐藏)所带来的好处?
我第一次读过一篇经典的文章,名为《关于将系统分解为模块的标准》。这对我来说很有意义,并且可能是OOP所基于的那些文章之一。结论: 我们试图通过这些示例来证明,根据流程图将系统分解为模块几乎总是不正确的。...然后每个模块都被设计为对其他模块隐藏这样的决定 以我未受过教育和缺乏经验的观点,函数式编程与本文完全相反。我的理解是函数式编程使数据流变得惯用了。数据从一个函数传递到另一个函数,每个函数都密切了解数据并在此过程中“更改”它。而且我想我已经看过Rich Hickey的演讲,他在演讲中谈到数据隐藏是如何被高估或不必要的,但我不确定。 首先,我想知道我的评估是否正确。FP范式和本文在哲学上是否不一致? 假设他们不同意,FP如何“弥补”缺乏数据隐藏的能力?也许他们牺牲了数据隐藏,但获得了X,Y和Z。我想知道为什么X,Y和Z比数据隐藏更有益的原因。 或者,假设他们不同意,也许FP认为数据隐藏很糟糕。如果是这样,为什么会认为数据隐藏不好? 假设他们同意,我想知道什么是FP数据隐藏实现。很明显在OOP中看到了这一点。您可以拥有一个private班级以外的人无法访问的字段。在FP中,没有明显的比喻。 我觉得还有其他问题要问,但我不知道我要问。也可以随意回答。 更新资料 我发现尼尔·福特(Neal Ford)的演讲中有一个非常相关的幻灯片。我将屏幕截图嵌入此处:


4
原型继承实际上与经典继承有何不同?
继承,多态性和封装是OOP的三个最不同的重要特征,从它们来看,继承如今具有很高的使用统计。我正在学习JavaScript,在这里,他们都说它具有原型继承,而且各地的人们都说它与经典继承大不相同。 但是,从实际使用的角度来看,我不明白它们有什么区别?换句话说,当您定义基类(原型)然后从中派生一些子类时,您都可以访问基类的功能性对象,并且可以在派生类上扩展功能。如果我们认为我所说的是继承的预期结果,那么为什么我们要使用原型还是经典版本呢? 为了使自己更加清楚,我认为原型继承和经典继承的有用性和使用方式没有区别。这导致我没有兴趣去了解它们为何不同的原因,因为它们都导致同一件事,OOAD。原型继承实际上(不是理论上)与经典继承有何不同?


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.