Questions tagged «object-oriented-design»

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

4
C#中哈希表和字典的实际大小限制
C#4词典或哈希表可以包含的项目数量的实际限制是多少,这些结构可以合理包含的字节总数。我将处理大量对象,并想知道这些结构何时开始遇到问题。 对于上下文,我将使用具有大量内存的64位系统。另外,我将需要使用某种形式或“键”来查找对象。鉴于性能需求,这些对象将需要驻留在内存中,并且许多对象将长期存在。 尽管我需要避免使用第三方或开放源代码库,但还是可以建议其他方法/模式。出于规范原因,我需要能够使用本机C#(或C ++ \ CLI)来构建它。

5
实体框架的域驱动设计的陷阱
我研究的许多DDD教程都涵盖了理论。它们都有基本的代码示例(Pluralsight和类似代码)。 在网络上,也有人尝试创建涵盖EF的DDD的教程。如果您只是简短地学习它们-您很快就会发现它们彼此之间有很大的不同。有些人建议保持应用程序最小化,并避免在EF之上引入其他层(例如,存储库),其他人则决定生成额外的层,甚至通过注入DbContext聚合根甚至违反SRP 。 如果要提出基于意见的问题,我深表歉意,但是... 在实践中,实体框架是功能最强大且使用最广泛的ORM之一。不幸的是,您不会找到涵盖DDD的综合课程。 重要方面: 实体框架可立即使用UoW和存储库(DbSet) 使用EF,您的模型具有导航属性 与EF所有的车型都始终可用的关闭DbContext(它们被表示为DbSet) 陷阱: 您不能保证子模型仅受“聚合根”影响-您的模型具有导航属性,可以修改它们并调用dbContext.SaveChanges() 与DbContext您可以访问每一个模型,从而规避聚合根 您可以通过将ModelBuilderin 标记为字段来通过in OnModelCreating方法来限制对根对象的子对象的访问-我仍然不认为这是进行DDD的正确方法,而且很难评估这种情况将来可能导致什么样的冒险(非常怀疑) 冲突: 如果没有实现返回聚合的另一层存储库,我们甚至无法部分解决上述陷阱 通过实现额外的存储库层,我们将忽略EF的内置功能(每个DbSet都已经是仓库)并且使应用程序过于复杂 我的结论是: 请原谅我的无知,但基于以上信息-要么是实体框架 不足以用于域驱动设计,或者域驱动设计是不完善且过时的方法。 我怀疑每种方法都有其优点,但是我现在已经完全迷失了,对如何将EF与DDD调和一无所知。 如果我错了-请问至少有人能详细介绍一下如何使用EF进行DDD的简单说明(甚至提供不错的代码示例)吗?

2
仅具有一个实例的Python类:何时创建(单个)类实例以及何时使用该类?
给定一个仅实例化一次的Python类,即该类中只有一个对象。我想知道在什么情况下创建单个类实例而不是直接与该类一起工作才有意义。 有一个类似的问题,但重点不同: 它是关于将全局变量和函数分组为一个类, 它不是特定于Python的。后者意味着它不考虑(在Python中)类也是对象的事实。 更新: 在Python中,我可以对类和对象执行以下操作: class A(object): pass A.some_state_var = True # Then later A.some_state_var = False my_a = A() my_a.some_state_var = True # Then later my_a.some_state_var = False 因此,我看不到在类和该类的实例之间进行选择如何与状态有关(在Python中)。我可以通过两者之一来保持状态。 此外,创建我的类/类实例的动机与执行Singleton要求无关。 另外,创建新的Type并不需要太多。 这样做的动机是将相关的代码和数据进行分组,并为其提供接口。这就是为什么我最初在类图中将其建模为类的原因。仅当涉及到实现时,我才开始怀疑是否要实例化此类。

5
在这种情况下,我应该选择组合还是继承?
考虑一个接口: interface IWaveGenerator { SoundWave GenerateWave(double frequency, double lengthInSeconds); } 此接口由许多类实现,这些类生成不同形状的波(例如SineWaveGenerator和SquareWaveGenerator)。 我想实现一个SoundWave基于音乐数据而不是原始声音数据生成类的类。它会收到音符的名称和以拍子(不是秒)为单位的长度,并在内部使用该IWaveGenerator功能来创建一个音符SoundWave。 问题是,应该NoteGenerator包含IWaveGenerator还是应该从IWaveGenerator实现中继承? 由于两个原因,我倾向于合成: 1 -它让我注入任何IWaveGenerator的NoteGenerator动态。另外,我只需要一个NoteGenerator类,而不是SineNoteGenerator,SquareNoteGenerator等等。 2-无需NoteGenerator公开由定义的较低级接口IWaveGenerator。 但是,我发布此问题是为了听取对此的其他意见,也许是我没有想到的要点。 顺便说一句:我会说NoteGenerator 从概念上讲是an,IWaveGenerator因为它生成SoundWaves。

3
是更好的做法是在类中预初始化属性,还是在过程中添加它们?
很抱歉,这是一个绝对如此愚蠢的问题,但是我很好奇目前存在的最佳做法,而且我似乎在Google上找不到很好的答案。 在Python中,我通常使用一个空类作为超级类数据结构容器(有点像JSON文件),并在此过程中添加属性: class DataObj: "Catch-all data object" def __init__(self): pass def processData(inputs): data = DataObj() data.a = 1 data.b = "sym" data.c = [2,5,2,1] 这给了我极大的灵活性,因为容器对象实际上可以存储任何东西。因此,如果出现了新的需求,我将其添加为DataObj对象的另一个属性(我在代码中传递了该属性)。 但是,最近(FP程序员)给我留下了深刻的印象,那就是这是一种糟糕的做法,因为这使得很难阅读代码。必须仔细阅读所有代码,以找出DataObj实际具有的属性。 问题:如何在不牺牲灵活性的情况下重写此代码,以实现更大的可维护性? 我可以采纳函数式编程中的任何想法吗? 我正在寻找最佳实践。 注意:一种想法是使用一个期望遇到的所有属性来预先初始化该类,例如 class DataObj: "Catch-all data object" def __init__(self): data.a = 0 data.b = "" data.c = [] def processData(inputs): data = …

4
我会遭受封装使用过度的困扰吗?
我在各种项目的代码中注意到了一些东西,这些东西似乎让我感到代码难闻,有些事情要做,但我无法解决。 在尝试编写“干净的代码”时,我倾向于过度使用私有方法,以使我的代码更易于阅读。问题在于代码确实更干净,但是测试起来也更加困难(是的,我知道我可以测试私有方法...),总的来说,这对我来说是个坏习惯。 这是一个类示例,该类从.csv文件中读取一些数据并返回一组客户(另一个具有各种字段和属性的对象)。 public class GroupOfCustomersImporter { //... Call fields .... public GroupOfCustomersImporter(String filePath) { this.filePath = filePath; customers = new HashSet<Customer>(); createCSVReader(); read(); constructTTRP_Instance(); } private void createCSVReader() { //.... } private void read() { //.... Reades the file and initializes the class attributes } private void readFirstLine(String[] inputLine) …

4
使用“混合”语言进行设计:面向对象的设计还是功能编程?
在过去的几年中,我喜欢使用的语言变得越来越“实用”。我现在使用的是一种“混合”语言:C#,F#,Scala。我喜欢使用与域对象相对应的类来设计我的应用程序,并使用使编码更容易,更简洁和更安全的功能功能(尤其是对集合进行操作或传递函数时)。 但是,当涉及到设计模式时,这两个世界会“冲突”。我最近遇到的特定示例是观察者模式。我希望生产者在创建或更改项目时通知其他一些代码(“消费者/观察员”,例如数据库存储,记录器等)。 我最初是这样“功能性地”完成的: producer.foo(item => { updateItemInDb(item); insertLog(item) }) // calls the function passed as argument as an item is processed 但是我现在想知道是否应该使用更多的“ OO”方法: interface IItemObserver { onNotify(Item) } class DBObserver : IItemObserver ... class LogObserver: IItemObserver ... producer.addObserver(new DBObserver) producer.addObserver(new LogObserver) producer.foo() //calls observer in a loop 两种方法的优缺点是什么?我曾经听过一位FP专家说,那里的设计模式仅是由于语言的局限性,这就是为什么功能语言很少的原因。也许这可能是一个例子? 编辑:在我的特定情况下,我不需要它,但是..您将如何以功能方式实现“观察者”的删除和添加?(即,您将如何实现模式中的所有功能?)例如,仅传递一个新函数?

9
SOLID与静态方法
这是我经常遇到的一个问题:假设有一个具有Product类的网上商店项目。我想添加一个功能,允许用户对产品发表评论。所以我有一个Review类,它引用一个产品。现在,我需要一种列出所有产品评论的方法。有两种可能性: (一种) public class Product { ... public Collection<Review> getReviews() {...} } (B) public class Review { ... static public Collection<Review> forProduct( Product product ) {...} } 通过查看代码,我将选择(A):它不是静态的,并且不需要参数。但是,我认为(A)违反了单一责任原则(SRP)和开放式封闭原则(OCP),而(B)没有违反: (SRP)当我想更改收集产品评论的方式时,我必须更改产品类。但是更改产品类的原因应该只有一个。那当然不是评论。如果我在产品中打包了与产品有关的所有功能,它将很快崩溃。 (OCP)我必须更改Product类以使用此功能对其进行扩展。我认为这违反了原则的“为变革而封闭”部分。在我收到客户的要求以实施评论之前,我认为产品已完成,然后“关闭”。 更重要的是:遵循SOLID原则,还是拥有更简单的界面? 还是我在这里做错了什么? 结果 哇,谢谢您的所有精彩回答!很难选择一个作为官方答案。 让我总结一下答案中的主要论点: 赞成(A):OCP不是法律,代码的可读性也很重要。 亲(A):实体关系应该是可导航的。两个类都可能知道这种关系。 pro(A)+(B):同时执行并将(A)中的任务委派给(B),这样就不太可能再次更改产品。 pro(C):将finder方法放在非静态的第三类(服务)中。 反对(B):阻止测试中的嘲笑。 我的大学在工作中还提供了一些其他功能: 亲(B):我们的ORM框架可以自动生成(B)的代码。 赞成(A):由于我们ORM框架的技术原因,在某些情况下,有必要独立于发现者去向而更改“封闭”实体。因此,无论如何,我将始终无法坚持使用SOLID。 对比(C):大惊小怪;-) 结论 我在当前项目中同时使用(A)+(B)和委派。但是,在面向服务的环境中,我将选择(C)。

7
从设计的角度来看,记录的最佳实践是什么?[关闭]
已关闭。这个问题需要更加集中。它当前不接受答案。 想改善这个问题吗?更新问题,使其仅通过编辑此帖子来关注一个问题。 6年前关闭。 我想将日志记录添加到当前正在处理的应用程序中。我之前添加了日志记录,这不是这里的问题。 但是从面向对象语言的设计角度来看,遵循OOP和模式的最佳记录实践是什么? 注意:我目前正在C#中执行此操作,因此显然欢迎使用C#中的示例。我也想看看Java和Ruby中的示例。 编辑:我正在使用log4net。我只是不知道插入它的最佳方法是什么。

10
属性的重点是什么?
以下是一些有关属性的参数和我的反参数: 比编写getter和setter方法更容易使用 Getter和setter方法对是代码的味道。编写起来更容易,就像使用Scantron表格并填写所有“ C”来简化数学测试失败一样。对于持久性,仅包含状态的对象不应使用getter / setter,而在持久性时应创建不可变的对象。 对于对象的消费者而言,重要的是它的作用,而不是它的作用方式。它的行为就是它所做的;它的状态是如何执行的。如果您发现自己关心对象的状态(持久性除外,尽管这也会破坏OO),那么您根本就没有在做OOP而失去了它的优势。 它们粗略地向消费者表明了性能 对于任何给定的财产,这可能会在将来发生变化。假设在版本1.0中,访问PropertyX只是返回一个字段。在版本1.5中,如果该字段为null,则PropertyX使用Null Object模式创建一个新的null对象。在2.0版中,该字段正在通过PropertyX中的getter方法进行进一步验证。 随着属性变得越来越复杂,使用属性的性能指标似乎越来越不真实。 他们比公共领域更好 这是真的。但是方法也是如此。 它们代表的是与方法根本不同的对象方面,并且对象的所有使用者都应注意这一点 您确定以上两个陈述都是正确的吗? 他们更容易打字,伙计 当然,打字myObject.Length比打字更容易myObject.Length(),但是不能用一点句法糖来解决吗? 为什么使用方法而不是属性? 没有性能保证。即使方法变得更复杂,API也会保持真实。如果消费者遇到性能问题,并且他们不依赖API的话,他们将需要分析其代码。 较少供消费者考虑。该酒店有塞特犬吗?一种方法肯定不会。 消费者从正确的OOP思维方式进行思考。作为API的使用者,我有兴趣与对象的行为进行交互。当我在API中看到属性时,它看起来很像状态。实际上,如果属性做得太多,它们甚至都不应该是属性,因此,实际上,API对用户来说是处于状态的属性。 API的程序员将更深入地考虑具有返回值的方法,并尽可能避免在此类方法中修改对象的状态。应当尽可能将命令与查询分开。 所以我问你,为什么要使用属性而不是方法?MSDN上的大多数要点本身就是代码的味道,它们既不属于属性也不属于方法。 (这些想法是在考虑了CQS之后想到的。)

2
面向对象的后期绑定
在Alan Kays的“面向对象的定义”中,有部分我不理解的定义: 对我而言,OOP意味着仅消息传递,本地保留和保护以及状态过程的隐藏以及所有事物的极端LateBinding。 但是“ LateBinding”是什么意思?如何在C#之类的语言上应用它?为什么这如此重要?

4
类复制模式?
我目前是我当前项目的独立开发人员。我从另一个离开公司的开发商那里继承了这个项目。它是C#中的模型视图控制器样式的Web应用程序。它使用实体框架进行对象关系映射。域模型中的类型有两组不同的类。一组用于与ORM进行交互,另一组用作MVC系统中的模型。例如,可能有两个类别,如下所示: public class Order{ int ID{get;set;} String Customer{get;set;} DateTime DeliveryDate{get;set;} String Description{get;set;} } 和 public class OrderModel{ String Customer{get;set;} DateTime DeliveryDate{get;set;} String Description{get;set;} public OrderModel( Order from){ this.Customer= from.Customer; // copy all the properties over individually } public Order ToOrder(){ Order result =new Order(); result.Customer = this.Customer; // copy all …

5
一系列操作的最佳OOP设计模式
我正在开发一个应用程序,该应用程序的模块按顺序执行以下财务操作: 当用户要求将一定金额转入她的银行帐户时: 检查现在是否可以进行任何交易?(交易只能在特定时间段内进行) 检查用户是否已要求提取最低金额 检查用户是否具有任何默认帐户 以上所有操作的结果均应记录。 如果满足以上所有条件,则执行交易。将来可能还会有其他检查。 哪种面向对象设计模式最适合上述情况?

4
什么是“过早抽象”?
我听过这个短语被扔掉了,对我来说,论点听起来完全是疯了(对不起,如果我在这里是稻草人,那不是我的意图),通常它遵循以下原则: 您不希望在知道一般情况之前先创建一个抽象,否则(1)您可能会将不属于您的东西放在抽象中,或者(2)忽略了重要的事情。 (1)对我来说,这听起来像程序员不够务实,他们已经假设事情会出现在最终程序中,而事实并非如此,因此他们使用的抽象程度很低,问题不是过早的抽象,它是过早的凝结。 (2)忽略重要的事情是一回事,完全有可能在规范中省略了某些事情,后来证明这很重要,解决这个问题的方法不是在发现自己时就浪费自己的资源和浪费资源。猜错了,这是从客户端获取更多信息。 我们应该始终从抽象到具体工作,因为这是最实用的做事方式,而不是相反。 如果我们不这样做,那么我们可能会误解客户,并创造需要更改的东西,但是如果我们仅构建客户以其自己的语言定义的抽象,那么我们就永远不会遇到这种风险(至少远不及承担风险)是在黑暗中带着某种凝结的镜头),是的,客户可能会改变对细节的想法,但是他们最初用来传达他们想要的内容的抽象往往仍然有效。 这是一个示例,假设客户希望您创建一个物品装箱机器人: public abstract class BaggingRobot() { private Collection<Item> items; public abstract void bag(Item item); } 我们正在从客户端使用的抽象中构建一些东西,而没有涉及我们不知道的事情的更多细节。这是非常灵活的,我已经看到这被称为“过早抽象”,而实际上假设套袋是如何实施还为时过早,可以说与客户讨论后,他们希望一次将多个袋装成袋。为了更新班级,我只需要更改签名,但是对于自下而上的人可能需要进行大范围的系统检修。 没有过早的抽象,只有过早的凝结。这句话有什么问题?我的推理的缺陷在哪里?谢谢。

2
有没有一种优雅的方法来检查域对象属性上的唯一约束,而又不将业务逻辑移入服务层?
我已经适应领域驱动设计大约8年了,即使经过了这些年,仍然有一件事困扰着我。那就是针对域对象检查数据存储中的唯一记录。 2013年9月,马丁·福勒(Martin Fowler)提到了TellDon'tAsk原则,如果可能的话,应将其应用于所有领域对象,然后应返回一条消息,说明操作如何进行(在面向对象的设计中,这通常是通过异常来完成的,操作失败)。 我的项目通常分为许多部分,其中两个部分是“域”(包含业务规则,没有其他内容,该域完全不考虑持久性)和“服务”。知道用于CRUD数据的存储库层的服务。 由于属于对象的属性的唯一性是域/业务规则,因此对于域模块来说应该很长,因此该规则正是它应该在的位置。 为了能够检查记录的唯一性,您需要查询当前数据集(通常是数据库),以查明是否存在另一个假设的记录Name。 考虑到域层对于持久性是无知的,并且不知道如何检索数据,而只知道如何对它们进行操作,因此它无法真正地访问存储库本身。 我一直在适应的设计如下所示: class ProductRepository { // throws Repository.RecordNotFoundException public Product GetBySKU(string sku); } class ProductCrudService { private ProductRepository pr; public ProductCrudService(ProductRepository repository) { pr = repository; } public void SaveProduct(Domain.Product product) { try { pr.GetBySKU(product.SKU); throw Service.ProductWithSKUAlreadyExistsException("msg"); } catch (Repository.RecordNotFoundException e) { // suppress/log …

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.