Questions tagged «design-patterns»

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

8
在关系数据库中建模单例的最佳方法
在为Web应用程序设计关系数据库架构时,经常会遇到一种情况,最终我创建了一个表,仅包含一行和一行。感觉那是设计它的错误方法,但是我无法提出任何明显更好的方法,或者那显然是“正确的方法”。 最近的示例是一个站点,该站点使用户可以手动控制主页上的内容。好吧,只有一个主页。我创建了一个表,其中包含构建主页的所有必要字段,例如包含描述性文本的区域的文本字段。一个用于存储大图像文件名称的字段。一些外键指向将在首页上显示的文章,等等。它虽然有效,但是只有一行的表感觉不对。 过去,我尝试了许多其他设计,例如允许主页表中包含多行并随机选择一个。我尝试添加一个名为“ active”的布尔字段,并随机选择一个活动主页。在应用程序逻辑中,我尝试在任何给定时间仅强制一行处于活动状态。我什至尝试不制作主页表,也不让所有其他项(例如文章)具有名称为featured_on_homepage之类的布尔字段。 在大多数情况下,我可以在设置文件中使用一堆常量来构建主页。设置文件的主要问题在于它在开发人员的控制之下。因为像主页内容这样的东西是用户要编辑的东西,所以它必须进入数据库。 在许多站点上,我没有这个问题,因为我可以通过查询来构建诸如首页之类的内容,例如选择五篇最新文章。但是,当我有严格要求的手动页面时,在数据库中对其建模就变得很棘手。但是想象一下,您有一张照片桌子和一张物品桌子。要求是首页要显示精确的五张照片,精确的三篇文章和两块由用户手动控制的任意文本。您如何在数据库中正确建模呢? 另外,除了首页以外,我在许多其他情况下都遇到了建模问题。这只是我能想到的最简单,最适用的示例。

4
并行层次结构-部分相同,部分不同
那里有很多类似的问题 1,2,3,4,但是在这个问题上似乎并非如此,解决方案也不是最优的。 假设多态性,泛型和混合可用,这是一个普遍的OOP问题。实际使用的语言是OOP Javascript(Typescript),但是在Java或C ++中,这是同样的问题。 我有并行的类层次结构,有时具有相同的行为(接口和实现),但有时每个都有其自己的“受保护”行为。像这样说明: 这仅是为了说明目的 ; 这不是实际的类图。阅读: Canvas(左)和SVG(右)层次结构共享公共层次结构(中心)中的任何内容。分享是指接口和实现。 仅左列或右列中的任何内容均表示特定于该层次结构的行为(方法和成员)。例如: 左和右层次结构都使用完全相同的验证机制,Viewee.validate()在通用层次结构上显示为单个方法()。 仅画布层次结构具有方法paint()。此方法在所有子项上调用paint方法。 SVG层次结构需要覆盖的addChild()方法Composite,但是canvas层次结构并非如此。 不能从两个侧面层次结构中混合构造。工厂确保做到这一点。 解决方案I-逗弄继承 Fowler的“逗趣分开继承”在这里似乎不起作用,因为两个相似之处之间存在一些差异。 解决方案II-Mixins 这是我目前唯一能想到的。这两个层次结构是分别开发的,但是在每个级别上,这些类都混合在公共类中,而这并不属于类层次结构。省略structural叉子,将如下所示: 请注意,每列将位于其自己的名称空间中,因此类名不会冲突。 问题 谁能看到这种方法的缺点?谁能想到更好的解决方案? 附录 这是一些示例代码,该如何使用。命名空间svg可以替换为canvas: var iView = document.getElementById( 'view' ), iKandinsky = new svg.Kandinsky(), iEpigone = new svg.Epigone(), iTonyBlair = new svg.TonyBlair( iView, iKandinsky ), iLayer = new svg.Layer(), iZoomer …

3
全局请求上下文-反模式?
今天我在和我的一位同事谈论Python Web框架以及我们对它们的印象。我告诉他,我认为Flask具有全局请求的气味很难闻,并且是一种反模式。 该文档说关于请求上下文: 相反,在请求处理期间,存在其他一些规则: 当请求处于活动状态时,上下文本地对象(flask.request和其他对象)指向当前请求。 任何代码都可以随时获取这些对象。 我认为我了解此设计决策背后的想法-使应用程序更简单。这只是一个折衷,就像在Thread Locals的情况下: 是的,使用线程本地化通常不是一个好主意。它们给不基于线程概念的服务器造成麻烦,并使大型应用程序难以维护。但是Flask并不是专门为大型应用程序或异步服务器设计的。Flask希望使其能够轻松快捷地编写传统的Web应用程序。 使用当前请求信息修补全局对象是否是反模式? 我相信是这样,因为从静态代码分析器的角度来看,它是一个全局状态,尽管事实并非如此。作为程序员,如果不仔细阅读文档,我将无法理解其工作原理。这对测试有影响。 将请求作为参数传递给视图不是一个好习惯吗?我认为它更具可读性,明确性且易于调试。并避免全局状态。

1
在大型对象层次结构中使用访问者模式
语境 我一直在使用对象层次结构(一个表达式树)使用“伪”访问者模式(伪,因为它不使用双调度): public interface MyInterface { void Accept(SomeClass operationClass); } public class MyImpl : MyInterface { public void Accept(SomeClass operationClass) { operationClass.DoSomething(); operationClass.DoSomethingElse(); // ... and so on ... } } 由于MyInterface的实现数量很多(约50个或更多),而且我不需要添加额外的操作,因此该设计非常舒适。 每个实现都是唯一的(它是一个不同的表达式或运算符),而某些实现是组合的(即,将包含其他运算符/叶节点的运算符节点)。 遍历当前是通过在树的根节点上调用Accept操作来执行的,后者依次在其每个子节点上调用Accept,依次类推...依次类推... 但是现在是时候需要添加一个新操作了,例如漂亮的打印: public class MyImpl : MyInterface { // Property does not come from MyInterface public string …

3
您如何在OOP中进行班级设计?
当我尝试设计OO解决方案时,通常使用CRC建模,其中列出了类名(名词),它们的作用(动词)以及它们与其他类的协作方式。 关于此名词-动词方法,此博客有以下要说的话 ...This approach, which I will call “noun and verb,” is so limited I’ll dare to call it brain damaged.... 我的问题是,使用OO方法是否存在更好的建模技术?

5
您是否利用了封闭式原则的好处?
开闭原理(OCP)指出对象应打开以进行扩展,但应关闭以进行修改。我相信我理解它,并将其与SRP结合使用来创建仅做一件事的类。而且,我尝试创建许多小的方法,使所有行为控件都可以提取到可以在某些子类中扩展或重写的方法中。因此,我最终得到了具有许多扩展点的类,包括:依赖项注入和组合,事件,委托等。 考虑以下简单的可扩展类: class PaycheckCalculator { // ... protected decimal GetOvertimeFactor() { return 2.0M; } } 现在说,例如,OvertimeFactor更改为1.5。由于上述类是为扩展而设计的,因此我可以轻松地子类化并返回一个不同的OvertimeFactor。 但是 ...尽管该类是为扩展而设计的,并且坚持使用OCP,但我将修改单个方法,而不是子类化和覆盖该方法,然后在IoC容器中重新连接对象。 结果,我违反了OCP尝试完成的部分工作。感觉就像是在偷懒,因为上面的内容要容易一些。我是否误解了OCP?我真的应该做些不同的事情吗?您是否以其他方式利用OCP的优势? 更新:根据答案,由于许多不同的原因,这个人为的例子似乎是一个糟糕的例子。该示例的主要目的是证明该类是通过提供以下方法来扩展的:该方法在被重写时将更改公共方法的行为,而无需更改内部或私有代码。不过,我绝对误会了OCP。

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的简单说明(甚至提供不错的代码示例)吗?

4
MVC和RESTful API服务
MVC非常简单。有一个模型,一个控制器和一个视图。当我们创建一个网站时,这一切都将作为一个整体' 客户端向服务器发送REST关键字请求->服务器将请求的URL与控制器操作相匹配->然后调用模型进行数据收集/处理,以获取结果->并将结果作为HTML页面(视图)返回给客户端。 如果我们正在谈论纯RESTful API Web服务该怎么办?然后,流程类似于“ 客户端向服务器发送REST关键字请求->服务器将请求的URL匹配到控制器操作->然后调用模型进行数据收集/处理,获得结果->并返回结果以JSON ' 返回给客户端。与以前相同,但是没有“视图” ...或者,可以将生成的JSON视为“视图”。从某种意义上讲,我们仅在利用MVC的MC部分。那是应该怎么做的?还是对于仅API服务而不是MVC还有其他更合适的模式吗?

2
实体组件系统对解耦/信息隐藏不是很可怕吗?
标题故意是双曲线的,可能只是我对模式的经验不足,但这是我的理由: 实现实体的“通常”或可以说是直接的方法是通过将它们实现为对象并将其子类化为常规行为。这导致了经典的问题“是或EvilTree的子类”。如果我们允许多重继承,就会出现钻石问题。我们可以代替拉的组合功能,并进一步向上层次导致神类,或者我们可以故意留出的行为在我们和类(使他们在极端情况下接口),以便可以实现本身-这会导致如果有一个代码复制。TreeEnemyTreeEnemyTreeEntityEvilTreeSomewhatEvilTree 实体组件系统试图通过将解决这一问题Tree和Enemy对象到不同的组件-比如Position,Health和AI-和执行系统,例如AISystem,根据AI决定改变一个Entitiy的位置。到目前为止,EvilTree还算不错,但是如果可以启动电源并造成损害该怎么办?首先,我们需要一个CollisionSystem和一个DamageSystem(我们可能已经有了这些)。CollisionSystem与进行通信的需求DamageSystem:每次两件事冲突时,CollisionSystem都会向发送一条消息,DamageSystem以便减少健康状况。损坏也会受到通电的影响,因此我们需要将其存储在某个地方。我们是否创建一个PowerupComponent附加到实体的新商品?但是然后DamageSystem需要知道一些它宁愿一无所知的东西-毕竟,有些东西会造成无法获得能量的伤害(例如Spike)。我们是否允许PowerupSystem修改StatComponent与该答案类似的用于损伤计算的?但是现在两个系统访问相同的数据。随着我们的游戏变得越来越复杂,它将变成无形的依赖图,其中组件在许多系统之间共享。在这一点上,我们可以使用全局静态变量并摆脱所有样板。 有解决此问题的有效方法吗?我曾经有过一个想法,就是让组件具有某些功能,例如,给StatComponent attack()它默认情况下只返回一个整数,但是可以在上电时进行组合: attack = getAttack compose powerupBy(20) compose powerdownBy(40) 这不能解决attack必须保存在多个系统访问的组件中的问题,但是如果我有足够的语言来支持它,至少我可以正确键入这些函数: // In StatComponent type Strength = PrePowerup | PostPowerup type Damage = Int type PrePowerup = Int type PostPowerup = Int attack: Strength = getAttack //default value, can be changed by systems getAttack: PrePowerup // these functions …

5
内存管理语言的参考计数模式?
Java和.NET都为你管理内存美妙的垃圾收集器,方便的方式快速释放的外部对象(Closeable,IDisposable),但只有当他们是由一个单一的对象所拥有。在某些系统中,可能需要由两个组件独立消耗资源,并且仅在两个组件都释放资源时才释放资源。 在现代C ++中,您可以使用来解决此问题,shared_ptr当所有shared_ptr都被销毁时,它将确定性地释放资源。 在面向对象的,不确定的垃圾收集系统中,是否有任何记录的,经过验证的模式来管理和释放昂贵的资源,这些资源没有一个所有者?

3
如何执行输入验证而没有异常或冗余
当我尝试为特定程序创建接口时,通常是在尝试避免引发依赖于未经验证的输入的异常。 因此,经常发生的事情是我想到了这样的一段代码(出于示例目的,这只是一个示例,不要介意它执行的功能,例如Java): public static String padToEvenOriginal(int evenSize, String string) { if (evenSize % 2 == 1) { throw new IllegalArgumentException("evenSize argument is not even"); } if (string.length() >= evenSize) { return string; } StringBuilder sb = new StringBuilder(evenSize); sb.append(string); for (int i = string.length(); i < evenSize; i++) { sb.append(' …

2
通过事务将业务逻辑与数据库逻辑分开
我们的应用程序包含三层。服务层提供外部API。BO层用于我们的业务逻辑,而DAO层用于我们的数据库连接。 假设每次更新文件时,我们还希望更改文件夹中的某些内容,例如“上次修改日期”。这需要在事务中完成。要么成功,要么文件和文件夹都被编辑。否则发生故障,事务将回滚,因此两个对象都处于先前状态。 “编辑文件时编辑文件夹”操作纯粹是业务逻辑。因此,这将意味着它属于BO层。但是,我们将Objectify用于数据库,因此要启动事务,我们需要调用ofy()。transact(...)。如果在BO层中调用此函数,则会破坏我们的设计,因为在业务层中将有数据库特定的调用(Objectify)。 什么是解决此问题的干净方法?

7
用OO语言实现对象状态?
我已经看过一些Java代码,它可以模拟赛车,其中包括基本状态机的实现。这不是经典的计算机科学状态机,而仅仅是一个可以具有多个状态并且可以基于一系列计算在其状态之间进行切换的对象。 为了描述问题,我有一个Car类,它带有一个嵌套的枚举类,该类为汽车的状态定义了一些常量(例如OFF,IDLE,DRIVE,REVERSE等)。在同一个Car类中,我有一个update函数,该函数基本上由一个大的switch语句组成,该语句打开汽车的当前状态,进行一些计算,然后更改汽车的状态。 据我所知,Cars状态仅在其自己的类中使用。 我的问题是,这是处理上述性质的状态机的最佳方法吗?听起来确实是最明显的解决方案,但过去我一直听说“ switch语句不好”。 我在这里看到的主要问题是,随着我们添加更多状态(如果认为必要),switch语句可能会变得非常大,并且代码可能变得笨拙且难以维护。 有什么更好的解决方案?

2
良好实践中的DRY原则?
我试图在编程中尽可能地遵循DRY原则。最近,我一直在学习OOP中的设计模式,最后又重复了一遍。 我创建了一个Repository模式以及一个Factory模式和Gateway模式来处理我的持久性。我在应用程序中使用数据库,但这没关系,因为如果我愿意,我应该能够换出网关并切换到另一种持久性。 我最终为自己创建的问题是,我为拥有的表数创建了相同的对象。例如,这些将是我需要处理表的对象comments。 class Comment extends Model { protected $id; protected $author; protected $text; protected $date; } class CommentFactory implements iFactory { public function createFrom(array $data) { return new Comment($data); } } class CommentGateway implements iGateway { protected $db; public function __construct(\Database $db) { $this->db = $db; } public function …

5
突变方法的单独界面
我一直在进行一些代码的重构,我想我可能已经迈出了第一步。我正在用Java编写示例,但我想它可能是不可知的。 我有一个Foo定义为的接口 public interface Foo { int getX(); int getY(); int getZ(); } 和一个实现 public final class DefaultFoo implements Foo { public DefaultFoo(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } public int getX() { return x; } public int getY() { …

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.