Questions tagged «object-oriented-design»

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

16
我们真的需要OO语言来管理软件复杂性吗?
这将是一个非技术性的软性问题,我不确定这是否是正确的平台。但是我是CS的初学者,所以我希望你们能容忍它。 在第一学期中,我们通过Java和UML介绍了OOP概念,例如封装,数据隐藏,模块化,继承等。(Java是我的第一门编程语言) 以我的理解,OOP是一种管理软件复杂性的方法。但是它的原理并不是新的或独特的,它们在某种意义上在所有工程领域都是通用的。 例如,汽车是一种非常复杂的结构,其复杂性由具有明确定义的行为和接口的模块化和封装组件的层次结构来管理。 但是我不明白引入新的编程范例的原因。我认为,用于管理复杂性的所有原理都可以通过过程编程语言来实现。例如,对于模块化,我们可以将程序分为许多小程序,这些小程序执行定义明确的任务,其代码包含在单独的文件中。这些程序将通过其定义明确的输入和输出相互交互。可以对文件进行保护(加密?)以实现封装。为了重新使用代码,我们只要在新程序中需要它们时就可以调用它们。这不是捕获所有的OOP还是我缺少非常明显的东西? 我不是要证明OOP可以管理复杂性。我认为确实可以。但是我认为,用于处理复杂性的所有原理(例如模块化,封装,数据隐藏等)都可以很容易地由过程语言实现。那么,如果我们不进行复杂性管理,为什么要真正实现面向对象设计呢?

15
使用布尔参数确定行为是否错误?
我不时看到一种“感觉”错误的做法,但是我不能很清楚地指出它的错误之处。也许这只是我的偏见。开始: 开发人员定义一个使用布尔值作为其参数之一的方法,然后该方法调用另一个,依此类推,最终使用该布尔值,仅用于确定是否要执行特定操作。例如,仅当用户具有某些权限时,或者如果我们(或不在)测试模式,批处理模式或实时模式下,或者仅当系统处于运行状态时,才可以使用此权限来执行操作一定的状态。 嗯,总有另一种方法可以做到,无论是通过查询何时该采取行动(而不是传递参数),还是通过该方法的多个版本或该类的多个实现,等等。我的问题是与其说如何改善它,不如说是真的不对(正如我怀疑的那样),如果真的对的话,那是什么问题。

14
四人帮是否彻底探索了“模式空间”?
自从我至少在10年前首次了解四人一组(GoF)设计模式以来,我一直以为这23种模式应该只是更大的东西的小样本,我称之为模式空间。假设的模式空间包括针对常见的面向对象软件设计问题的所有推荐解决方案(已知或未知)。 因此,我期望已知和记录在案的设计模式数量会大大增加。 它没有发生。GoF书问世20多年来,Wikipedia文章中仅列出了12种其他模式,其中大多数都不如原始模式流行。(我未在此处包括并发模式,因为它们涉及特定主题。) 是什么原因 GoF模式集实际上是否比我想象的更全面? 寻找新模式的兴趣下降了吗,也许是因为发现它们在软件设计中并不是那么有用? 还有吗

17
从不存在返回值的函数/方法中返回NULL或空值更好吗?
我在这里寻找建议。我正在努力在不存在返回值或无法确定返回值的情况下从方法返回NULL还是返回空值更好。 以以下两种方法为例: string ReverseString(string stringToReverse) // takes a string and reverses it. Person FindPerson(int personID) // finds a Person with a matching personID. 在中ReverseString(),我会说返回一个空字符串,因为返回类型是字符串,因此调用者期望得到。同样,通过这种方式,调用方将不必检查是否返回了NULL。 在中FindPerson(),返回NULL似乎更合适。无论是否new Person()返回NULL或空的Person Object(),调用者都必须在对其进行任何操作(如调用UpdateName())之前检查一下Person对象是否为NULL或为空。因此,为什么不只在此处返回NULL,然后调用方只需检查NULL。 还有其他人为此感到挣扎吗?任何帮助或见解表示赞赏。

10
这是否违反了《里斯科夫换人原则》?
假设我们有一个Task实体列表和一个ProjectTask子类型。任务可以随时关闭,除非ProjectTasks状态为“已启动”的任务无法关闭。用户界面应确保关闭启动选项ProjectTask永远不会可用,但是域中存在一些保护措施: public class Task { public Status Status { get; set; } public virtual void Close() { Status = Status.Closed; } } public class ProjectTask : Task { public override void Close() { if (Status == Status.Started) throw new Exception("Cannot close a started Project Task"); base.Close(); } } 现在,在调用Close()Task时,如果调用ProjectTask处于启动状态,则有可能失败,而如果它是基本Task,则调用不会失败。但这是业务需求。它应该失败。可以认为这违反了Liskov替代原则吗?

6
真正的“业务逻辑”是什么?
自2009年开始使用PHP以来,我一直从事Web开发。当我搬到ASP.NET时,我听到了很多有关DDD和OOAD的信息,其中很多重点都放在了这种“业务逻辑”和“业务规则”上。关键是,到目前为止,我开发的所有应用程序都与CRUD操作有关,而我在实践中从未见过这些东西。 我简直无法想象这些东西在实践中到底会是什么。那么,这个业务逻辑到底是什么?它如何适合应用程序?我知道这些方法是作为领域模型中的方法实现的,但是这些方法可能是什么,以及它们在应用程序中的可能位置?

13
您如何通过遵循干净的代码实践来证明编写更多代码是合理的?
主持人笔记 这个问题已经有十七个答案。在发布新答案之前,请阅读现有答案,并确保您的观点尚未得到适当覆盖。 我一直遵循罗伯特·马丁(Robert Martin)的“清洁代码”书中推荐的一些做法,尤其是那些适用于我使用的软件类型的做法以及对我有意义的做法(我不遵循它作为教条) 。 但是,我注意到的一个副作用是,我编写的“干净”代码比没有遵循某些实践的代码要多。导致这种情况的具体做法是: 封装条件 所以代替 if(contact.email != null && contact.emails.contains('@') 我可以写一个像这样的小方法 private Boolean isEmailValid(String email){...} 用另一个私有方法替换内联注释,以便方法名称描述自身,而不是在其顶部添加内联注释 一堂课只有一个改变的理由 还有其他一些。关键是,可能是30行的方法最终成为一个类,这是因为微小的方法可以替换注释并封装条件等。当您意识到自己有这么多的方法时,它对将所有功能都放在一个类中,实际上它本来应该是一种方法。 我知道任何极端的做法都是有害的。 我正在寻找答案的具体问题是: 这是编写干净代码的可接受的副产品吗?如果是这样,我可以使用哪些论据来证明已编写了更多LOC这一事实呢? 该组织并不特别在意更多的LOC,但是更多的LOC可能会导致非常大的类(同样,为了便于阅读,可以用长方法代替一堆只使用一次的辅助函数)。 当您看到一个足够大的课程时,它给人的印象是该课程很忙,并且其职责已经结束。因此,您最终可能会创建更多的类来实现其他功能。结果就是很多类,都借助于许多小的辅助方法来“做一件事”。 这是特定的关注点……这些类可以是一个单一的类,仍然可以实现“一件事”,而无需许多小方法的帮助。它可能是单个类,可能带有3或4个方法以及一些注释。

12
如果我们重写SetWidth和SetHeight方法,为什么Square从Rectangle继承会出现问题?
如果Square是Rectangle的一种类型,那么为什么Square无法从Rectangle继承?还是为什么设计不好? 我听说有人说: 如果您使Square从Rectangle派生,那么Square应该可以在您期望矩形的任何地方使用 这里有什么问题?为何Square可以在您期望矩形的任何地方使用?仅当我们创建Square对象,并且重写Square的SetWidth和SetHeight方法时,它才可用,为什么会有任何问题呢? 如果您在Rectangle基类上具有SetWidth和SetHeight方法,并且Rectangle引用指向一个Square,则SetWidth和SetHeight毫无意义,因为设置一个将更改另一个以匹配它。在这种情况下,Square无法通过带有矩形的Liskov替代测试,并且从Square继承Square的抽象是一个不好的选择。 有人可以解释以上论点吗?同样,如果我们在Square中重写SetWidth和SetHeight方法,它是否可以解决此问题? 我也听说过: 真正的问题是我们不是在建模矩形,而是在“舒适的矩​​形”上建模,即在创建后可以修改宽度或高度的矩形(并且我们仍然将其视为同一对象)。如果我们以这种方式看待矩形类,很明显,正方形不是“可接受的矩形”,因为正方形无法重塑,并且仍然是正方形(通常)。在数学上,我们看不到问题,因为在数学环境中可变性甚至都没有意义 在这里,我认为“可调整大小”是正确的术语。矩形是“可调整大小的”,正方形也是如此。我在上述论点中缺少什么吗?可以像调整任何矩形一样调整正方形的大小。

9
为什么要使用依赖注入?
我很难找到有关为什么应该使用依赖项注入的资源。我看到的大多数资源都说明它只是将一个对象的实例传递给另一个对象的实例,但是为什么呢?这是仅用于更干净的体系结构/代码,还是会整体上影响性能? 为什么要执行以下操作? class Profile { public function deactivateProfile(Setting $setting) { $setting->isActive = false; } } 而不是以下? class Profile { public function deactivateProfile() { $setting = new Setting(); $setting->isActive = false; } }

4
富域模型-行为如何准确地适应?
在Rich与Anemic领域模型的辩论中,互联网充满了哲学上的建议,但缺乏权威的例子。这个问题的目的是找到适当的领域驱动设计模型的明确指南和具体示例。(理想情况下为C#。) 对于一个实际示例,这种DDD实现似乎是错误的: 下面的WorkItem域模型不过是属性包,由Entity Framework用于代码优先数据库。按照福勒的说法,这是贫血的。 WorkItemService层显然是对域服务的常见误解。它包含WorkItem的所有行为/业务逻辑。Per Yemelyanov等人认为,这是程序性的。(第6页) 因此,如果以下内容是错误的,我该怎么做呢? 该行为,即AddStatusUpdate或Checkout,应该属于WorkItem类吗? WorkItem模型应具有哪些依赖关系? public class WorkItemService : IWorkItemService { private IUnitOfWorkFactory _unitOfWorkFactory; //using Unity for dependency injection public WorkItemService(IUnitOfWorkFactory unitOfWorkFactory) { _unitOfWorkFactory = unitOfWorkFactory; } public void AddStatusUpdate(int workItemId, int statusId) { using (var unitOfWork = _unitOfWorkFactory.GetUnitOfWork<IWorkItemUnitOfWork>()) { var workItemRepo = unitOfWork.WorkItemRepository; var workItemStatusRepo …


10
我提出的设计通常比同事的设计差-我如何变得更好?[关闭]
我从事编程已有两年了,在解决问题和创建中小型脚本方面通常都不错,但是,我通常不擅长以面向对象的方式设计大型程序。几个问题 最近,一位与我有着多年经验的同事正在研究一个问题。我在解决问题上的时间比他长,但是,他提出了一个更好的解决方案,最后我们将使用他的设计。这真的影响了我。我承认他的设计更好,但是我想提出一个和他一样好的设计。我什至正在考虑辞职。不知道为什么,但是突然之间,我感到有些压力,例如,大三学生会怎么看我等等?正常吗 还是我对此考虑太多了? 我的工作涉及使用Python编程。我尝试阅读源代码,但是您认为我如何提高我的设计技能?我应该学习什么好书或软件吗? 请赐教。非常感谢您的帮助。

12
有一个标志来指示是否应该抛出错误
我最近开始在一个与一些年龄较大的开发人员(大约50岁以上)一起工作的地方。他们致力于处理无法解决系统故障的航空关键应用。结果,较老的程序员倾向于以这种方式进行编码。 他倾向于在对象中放入一个布尔值,以指示是否应该引发异常。 例 public class AreaCalculator { AreaCalculator(bool shouldThrowExceptions) { ... } CalculateArea(int x, int y) { if(x < 0 || y < 0) { if(shouldThrowExceptions) throwException; else return 0; } } } (在我们的项目中,该方法可能会失败,因为我们正在尝试使用当时无法使用的网络设备。区域示例仅是异常标志的示例) 对我来说,这似乎是一种代码气味。编写单元测试变得有些复杂,因为每次都必须测试异常标志。另外,如果出现问题,您是否想立即知道?确定如何继续是呼叫者的责任吗? 他的逻辑/理由是我们的程序需要做一件事,向用户显示数据。任何其他不会阻止我们这样做的异常都应忽略。我同意不应忽视它们,而应该冒泡并由适当的人员来处理,而不必为此处理标志。 这是处理异常的好方法吗? 编辑:只是为了提供更多有关设计决策的信息,我怀疑这是因为如果该组件失败,程序仍可以运行并完成其主要任务。因此,当用户可以正常工作时,我们不想抛出异常(不处理它?)并让它删除程序。 编辑2:为了提供更多上下文,在本例中,该方法被调用来重置网卡。当网卡断开连接并重新连接时,会出现问题,它被分配了另一个IP地址,因此Reset将引发异常,因为我们将尝试使用旧的IP重置硬件。

10
这是什么意思?“用户不应该决定它是否是管理员。特权或安全系统应如此。”
问题中使用的示例将最少的数据传递给函数,以确定是否用户是管理员的最佳方法。一个常见的答案是: user.isAdmin() 这引起了评论,该评论被重复了多次并被多次投票: 用户不应该确定它是否是管理员。特权或安全系统应该。与课程紧密联系并不意味着将其纳入课程是一个好主意。 我回答, 用户没有决定什么。用户对象/表存储有关每个用户的数据。实际用户不会改变自己的一切。 但这没有效果。显然,存在潜在的视角差异,这导致沟通困难。有人可以向我解释为什么user.isAdmin()不好,并绘制一个简短的草图来“完成”吗? 确实,我看不到将安全与受保护系统分开的优势。任何安全性文字都将要求从一开始就将安全性设计到系统中,并在开发,部署,维护乃至报废的每个阶段都要加以考虑。它不是可以固定在侧面的东西。但到目前为止,此评论有17票赞成票,表明我错过了一些重要的内容。

9
只有一个(公共)方法的类是否有问题?
我目前正在从事一个软件项目,该项目对视频监控镜头进行压缩和索引编制。压缩的工作方式是分割背景和前景对象,然后将背景另存为静态图像,并将前景另存为子画面。 最近,我开始复习我为该项目设计的一些课程。 我注意到有许多类只有一个公共方法。其中一些类是: VideoCompressor(使用一种compress方法,该方法接收类型的输入视频RawVideo并返回类型的输出视频CompressedVideo)。 VideoSplitter(使用一种split方法,该方法接收类型的输入视频RawVideo并返回2个输出视频的向量,每个类型均为RawVideo)。 VideoIndexer(使用index接收类型为type的输入视频RawVideo并返回类型为video的视频索引的方法VideoIndex)。 我发现自己实例每个班只是为了让像电话VideoCompressor.compress(...),VideoSplitter.split(...),VideoIndexer.index(...)。 从表面上看,我确实认为类名足以说明其预期功能,实际上它们是名词。相应地,它们的方法也是动词。 这真的有问题吗?

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.