Questions tagged «design-patterns»

设计模式是解决软件设计中常见问题的通用可重用解决方案。

7
规避巫师和战士中的规则
在这一系列博客文章中,Eric Lippert使用向导和战士作为示例描述了面向对象设计中的问题,其中: abstract class Weapon { } sealed class Staff : Weapon { } sealed class Sword : Weapon { } abstract class Player { public Weapon Weapon { get; set; } } sealed class Wizard : Player { } sealed class Warrior : Player { } 然后添加一些规则: 战士只能使用剑。 向导只能使用人员。 …

3
C#模式可以清晰地处理“自由功能”,避免使用Helper风格的“实用程序包”静态类
我最近正在查看一些浮动的Helper风格的“实用程序包”静态类,这些静态类围绕我使用的一些大型C#代码库进行浮动,基本上类似于以下非常简短的代码段: // Helpers.cs public static class Helpers { public static void DoSomething() {} public static void DoSomethingElse() {} } 我审查过的具体方法是 彼此之间几乎没有关系 没有明确的状态在调用之间持续存在, 小,和 每一种都由各种不相关的类型消耗。 编辑:上面的内容并非旨在列出所指控的问题。这是我正在审查的特定方法的共同特征的列表。帮助答案提供更多相关解决方案的上下文。 仅针对此问题,我将把这种方法称为GLUM(通用轻量级实用程序方法)。部分地意在“消极”的负面含义。抱歉,这是愚蠢的双关语。 即使撇开我自己对GLUM的默认怀疑态度,我也不喜欢以下内容: 静态类仅用作命名空间。 静态类标识符基本上是没有意义的。 添加新的GLUM时,要么(a)毫无理由地触摸此“ bag”类,要么(b)创建一个新的“ bag”类(这本身通常不成问题;糟糕的是,新的静态类通常只会重复不相关性问题,但方法更少。 元的命名无疑也是可怕的,非标准的,通常内部不一致,无论是Helpers,Utilities或什么的。 什么是重构的合理好简单的模式,最好解决上述问题,并且最好轻触一下? 我可能应该强调:我正在处理的所有方法都是成对的彼此无关。似乎没有一种合理的方法可以将它们分解为更细粒度但仍为多成员的静态类方法包。

3
在文件的开头写一些您仅在结尾知道的内容
背景:我正在编写微控制器C代码来编写EBML文件。EBML就像是带有嵌套元素的二进制XML,但是不是开始和结束标签,而是一个开始ID,长度和数据。我将其写入低功耗应用程序的外部Flash中,因此我希望将Flash的访问量降至最低。内存也很有限,因为没有一件事情容易。 当我可以将整个EBML元素保留在内存中时,生成它很容易,因为在知道长度之后,我可以返回并填写每个元素的长度。问题是当我无法将整个元素保存在内存中时该怎么办。我看到的选项是: 写出我所知道的内容,然后返回并添加长度(最简单,但是添加的闪存访问量比我想要的更多) 在开始编写每个元素之前,先计算它们的长度(相对容易,但是需要很多处理器时间) 一旦我的内存填满,就切换模式,这样我就可以继续浏览数据,但是仅是为了计算已经在内存中保留的元素的长度。然后写出内存中的内容,然后返回并继续从上次中断的地方处理数据。(到目前为止,我最喜欢的选项) 在需要编写元素且最终长度未知时,为它们提供最大或最坏情况的长度。(比上面更容易,但可能适得其反并浪费空间) 问题:看来这应该是人们思考过的相对普遍的问题。我知道在形成一些数据包时也会发生这种情况。我在这里缺少更好/更常见/更容易接受的技术吗?还是我可以搜索的一些术语?

4
在复杂的以域为中心的应用程序中,用于基本CRUD操作的DDD方法
我的公司正在从头开始重写我们的Web应用程序。它是大型企业级应用程序,在金融行业中具有复杂的领域。 我们使用ORM(实体框架)进行持久化。 本质上,我们的应用程序的一半集中在从用户那里收集原始数据,进行存储,然后包含大部分实际域逻辑的应用程序的另一半使用原始数据来创建我们的域图片,该域图片与原始数据有很大的不同原始输入,并将其传递到calc引擎,运行calcs,并吐出结果,然后将结果显示给用户。 在使用层的DDD方法中,CRUD操作似乎遍历域层。但至少在我们看来,这似乎没有道理。 例如,当用户转到编辑屏幕以更改投资帐户时,屏幕上的字段是存储在数据库中的确切字段,而不是以后用于计算的域表示形式。那么,当编辑屏幕需要数据库表示形式(原始输入)时,为什么要加载投资帐户的域表示形式呢? 在用户单击投资帐户屏幕上的“完成”,并对控制器执行POST之后,控制器现在几乎具有需要保存的投资帐户的确切数据库表示形式。但是出于某种原因,我应该加载域表示以进行修改,而不是仅将控制器模型直接映射到数据库模型(实体框架模型)? 因此,从本质上讲,我是将数据模型映射到域模型,以便可以将其映射回数据模型以持久化。这有什么意义?

1
业务逻辑与服务层
我读了这个答案:https : //softwareengineering.stackexchange.com/a/234254/173318请更正我的理解。 业务规则是指现实世界中的业务步骤列表(无代码)。 业务逻辑是指将业务规则转换为代码的过程,并将这些代码束/种类称为“业务逻辑”。 服务层的用途是什么?如果我读了这个答案,听起来与业务逻辑没什么不同https://stackoverflow.com/a/4817935/4190539 服务层是业务逻辑和存储库相遇的地方吗?

2
是什么使迭代器成为设计模式?
我一直在想,与其他类似构造相比,使Iterator变得特别的原因是什么,并且使“ 四人帮”将其列为设计模式。 迭代器基于多态性(具有公共接口的集合的层次结构)和关注点分离(对集合的迭代应独立于数据的结构方式)。 但是,如果我们将集合的层次结构替换为例如数学对象的层次结构(整数,浮点数,复数,矩阵等),而迭代器由代表这些对象的某些相关操作(例如幂函数)的类替换,该怎么办?类图将是相同的。 我们可能会发现更多类似的示例,例如Writer,Painter,Encoder和更好的示例,它们的工作方式相同。但是,我从未听说过其中任何一种称为设计模式。 那么,什么使Iterator特别呢? 是否因为需要可变状态来将当前位置存储在集合中而变得更加复杂,这是事实吗?但是,通常不认为可变状态是理想的。 为了阐明我的观点,让我举一个更详细的例子。 这是我们的设计问题: 假设我们有一个类的层次结构,并且在这些类的对象上定义了一个操作。每个类的操作接口相同,但实现方式可以完全不同。还假定对同一对象(例如具有不同的参数)多次应用该操作是有意义的。 这是解决我们设计问题的明智解决方案(实际上是迭代器模式的概括): 为了分离关注点,不应将操作的实现作为功能添加到原始类层次结构(操作数对象)中。由于我们想在同一个操作数上多次应用该操作,因此它应该由一个持有对该操作数的引用的对象来表示,而不仅仅是由函数表示。因此,操作数对象应提供一个函数,该函数返回表示操作的对象。该对象提供执行实际操作的功能。 一个例子: 有一个基类或接口MathObject(愚蠢的名字,我知道,也许有人有更好的主意。)与派生类MyInteger和MyMatrix。对于每个MathObject操作,Power都应定义一个允许计算平方,立方等的运算。所以我们可以写(用Java): MathObject i = new MyInteger(5); Power powerOfFive = i.getPower(); MyInteger square = powerOfFive.calculate(2); // should return 25 MyInteger cube = powerOfFive.calculate(3); // should return 125

4
如何清楚定义边界上下文的边界
经过一个月左右的阅读和研究DDD,我决定开始自己的项目,并使用这些有限的上下文创建DDD。 客户群 产品展示 命令 开票 每个有界上下文都有其余的API作为表示层,域层,持久层。 到目前为止,代码运行顺利,但是来自一个单一的世界,我仍在尝试找出以下内容: 当我想创建一个新客户时,发出新发票,创建我想要的新订单,例如访问国家列表。我要: a)在每个卑诗省创建一个国家列表 b)创建一个国家BC-> API并使用它来获取可用国家的列表 c)使用第三方API并通过每个BC中的反腐败层提取数据 当使用反腐败层或适配器层与第三方API集成时,我的域模型中必须包含哪些数据?例如,如果我想将zendesk API与Client BC集成在一起。我是否仅需要我域中的ticketID,还是必须从Zendesk中提取要在Client BC中访问和使用的所有数据? 如果我的MVC应用程序实际上是从API(我的受限上下文的表示层)获取数据的,那么我很难清楚地定义每个BC的边界。这是否意味着经过适当设计的BC可以为单个MVC控制器提供服务,而无需使用其他API?

2
当观察者彼此不独立时,观察者模式是否合适?
我有一个class Car具有2个属性的属性:int price和boolean inStock。它还持有List的abstract class State(空类)。可以在汽车上应用两种状态,每种状态由其自己的类表示:class Upgrade extends State和class Shipping extends State。 A Car可以容纳2个状态中的任何一个。各州有以下规则: Upgrade:加到1汽车本身适用的每个州的价格上。 Shipping:如果Shipping列表中至少有1个状态,则将inStock其设置为false。 例如,以price = 1和开头inStock = true: add Shipping s1 --> price: 1, inStock: false add Upgrade g1 --> price: 1, inStock: false add Shipping s2 --> price: 2, inStock: false add Shipping s3 --> price: …

1
如何将命令对象与正确的接收者关联?
我尝试使用命令模式在项目中实现撤消和重做 public abstract class Command { protected Form Receiver { set; get; } protected HtmlElement Element { set; get; } abstract public void ReDo(); abstract public void UnDo(); public Command(Form receiver) { this.Receiver = receiver; } } class AddElementCmd : Command { public AddElementCmd(HtmlElement elem, Form receiver) : base(receiver) { …

1
仅在很少有写入的情况下才使用事件源吗?
我正在阅读事件源,不能停止问自己,这是否仅在非常罕见的情况下才有意义,在这种情况下,写操作很少或需要进行军事级审核。 具有非凡用途的非例外系统每天可能会产生成百上千的写入,相当于每年运行一百万或2次写入(因此发生事件)。与从传统存储中直接读取的内容相比,合并数百万个对象(事件)只是为了获得当前状态,这听起来很荒谬。但是,事件源位于某些性能最高的系统(例如LMAX)的背后。 那么,我想念什么?从事件流恢复状态是否通常已经完成?还是这种想法很少需要这样做,而是完全使用其他存储来进行常规操作(即使用CQRS的查询存储),并且仅在特殊情况下(例如复制,审核等)从事件中恢复?

8
防范数据库中错误的空条目的设计和实践
程序的一部分从数据库中的许多表和列中获取数据进行处理。有些列可能是null,但是在当前处理上下文中这是一个错误。 从理论上讲,这不会发生,因此,如果这样做,则表明数据错误或代码中存在错误。错误具有不同的严重性,具体取决于哪个字段null。也就是说,对于某些字段,应停止处理并通知某人;对于其他字段,应允许该处理继续进行,而仅通知某人。 是否有任何好的架构或设计原则来处理稀有但可能的null条目? 解决方案应该可以用Java来实现,但是我没有使用标记,因为我认为问题在某种程度上与语言无关。 我的一些想法: 使用NOT NULL 最简单的方法是在数据库中使用NOT NULL约束。 但是,如果原始数据插入比随后的处理步骤更重要,该怎么办?因此,如果插入内容将a null放入表中(由于错误或什至出于某些合理的原因),我不希望插入操作失败。假设程序的更多部分取决于插入的数据,但不取决于此特定列。因此,我宁愿冒险在当前处理步骤而不是插入步骤中出错。这就是为什么我不想使用NOT NULL约束的原因。 天真的取决于NullPointerException 我可以使用数据,就像我期望它始终存在一样(这确实应该如此),并在适当的级别上捕获生成的NPE(例如,以便停止当前条目的处理,而不是整个处理进度) )。这是“快速失败”的原则,我经常喜欢它。如果这是一个错误,至少我会得到一个已记录的NPE。 但是后来我失去了区分各种丢失数据的能力。例如,对于某些丢失的数据,我可以将其省略,但是对于其他一些数据,应停止处理并通知管理员。 null在每次访问之前进行检查并引发自定义异常 自定义异常可以让我根据异常来决定正确的操作,因此这似乎是可行的方法。 但是,如果我忘记在某个地方检查该怎么办?然后,我还会使用从未有过或很少有期望的空检查(因此绝对不是业务逻辑流程的一部分)使我的代码混乱。 如果我选择这种方式,哪种模式最适合该方法? 欢迎对我的方法提出任何想法和意见。还有任何更好的解决方案(模式,原理,代码或模型的更好体系结构等)。 编辑: 还有一个约束,因为我使用ORM进行从DB到持久性对象的映射,因此在该级别上执行null检查将不起作用(因为在null不会造成任何危害的部分中使用了相同的对象) 。我添加此内容是因为到目前为止提供的答案都提到了该选项。


6
如何在switch语句中减少switch?
因此,我正在基于数据库中的两个人创建一种称呼行的方法。 有四个参数:两个名称(name1和name2)和两个性别(gender和gender2)。 对于每种性别组合,我都有不同的输出。 例如:如果性别1为M(man)且性别2也为M,则输出应为: Dear Sir name1 and Sir name2, 此时,我的开关如下所示: switch(gender1){ case 'M': switch(gender2){ case 'M': printf("Dear Sir %s and Sir %s", name1, name2); break; case 'W': printf("Dear Sir %s and Madame %s", name1, name2); break; case 'R': ... } break; case 'W': switch(gender2){ case 'M': printf("Dear Madame %s …

4
如何在不强制进行层次结构的情况下使对象彼此交互和通信?
我希望这些问题能使我的问题更清楚-但是,我完全理解它们是否愿意,所以请让我知道是否是这种情况,然后我将尝试使自己更加清楚。 认识BoxPong,这是我做的非常简单的游戏,以熟悉面向对象的游戏开发。拖动框以控制球并收集黄色的东西。 制作BoxPong可以帮助我提出一个基本问题:除其他事项外,我如何才能具有相互交互的对象?换句话说,有没有一种方法使对象不是分层的而是共存的?(我将在下面进一步详细介绍。) 我怀疑对象共存的问题是一个普遍的问题,因此我希望有一个既定的解决方法。我不想重新发明方形齿轮,因此我想寻找的理想答案是“这是一种通常用于解决您的问题的设计模式”。 尤其是在像BoxPong这样的简单游戏中,很明显,在同一级别上存在或应该存在少量对象。有一个盒子,有一个球,有一个收藏品。我可以用面向对象的语言表达的所有内容,尽管看起来似乎都是严格的HAS-A关系。这是通过成员变量完成的。我不能只是开始ball并让它做它的事情,我需要它永久地属于另一个对象。我已经设定,使游戏的主要对象有一个箱子,并依次盒子有一个球,并有一个比分反超。每个对象也都有一个update()方法,该方法计算位置,方向等,我走了类似的方法还有:我所说的主要游戏对象的更新方法,它调用了所有儿童的更新方法,它们依次调用所有的更新方法他们的孩子。这是我看到的制作面向对象游戏的唯一方法,但我认为这不是理想的方法。毕竟,我不会完全把球看作是属于盒子的东西,而是要处于同一水平并与之交互。我想可以通过将所有游戏对象都转换成主要游戏对象的成员变量来实现,但是我看不出有什么解决方法。我的意思是……撇开明显的混乱,如何让球和盒子互相认识,也就是互动? 还存在对象之间需要传递信息的问题。我有很多为SNES编写代码的经验,您几乎一直可以访问整个RAM。假设您要为Super Mario World定制敌人,并且希望它删除Mario的所有硬币,然后只存储零以解决$ 0DBF,这没问题。没有任何限制说敌人无法访问玩家的状态。我想我被这种自由宠坏了,因为对于C ++之类的东西,我经常发现自己在想如何使其他对象(甚至全局对象)可以访问值。 以BoxPong为例,如果我希望球从屏幕边缘弹起怎么办?width和height是的属性Game类,ball可以访问它们。我可以传递这些类型的值(通过构造函数或需要它们的方法),但是这只是对我的不好的做法。 我想我的主要问题是我需要对象彼此了解,但是我看到的唯一方法是严格的层次结构,这是丑陋且不切实际的。 我听说过C ++上的“朋友类”,并且知道它们是如何工作的,但是如果它们是最终解决方案,那么为什么我看不到friend每个C ++项目中都充斥着关键字呢?并不是每种OOP语言都存在这个概念吗?(我最近才了解到的函数指针也是如此。) 预先感谢您提供任何形式的答案-再次提醒您,如果有部分内容对您没有意义,请告诉我。

1
“通量”与纯函数式反应式编程之间是什么关系?
据我了解,Flux是一种技术,用于单向处理应用程序的数据流,将状态与程序的其余部分隔离在只读的独立“存储区”中,该存储区可以通过侦听来更改其自身的状态。由视图发出并由调度程序调度的“动作”。或者,简而言之-一种控制状态的方法。 如果是正确的话,它与功能反应式编程有何关系?由于FRP对状态有非常强的控制力,因此我想这是实际上解决相同问题的互斥技术。因此,如果使用FRP库(例如Elm),则Flux几乎没有用。它是否正确?

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.