Questions tagged «design-patterns»

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

4
在创建松耦合设计上应该投入多少精力?
我目前正在学习设计模式。 我认为大多数人都同意这些模式是很好的工具,但应谨慎使用,而不是所有问题的答案。过多使用它们会使应用程序过于复杂,几乎没有好处。模式应仅在可能是最佳解决方案或有助于创建好的解决方案的地方使用(您同意吗?)。 考虑到这一点: 我正在阅读的书(Head First设计模式)经常强调松散耦合的重要性。这种松散耦合是通过遵循以下原则来实现的,例如“对接口编程,而不是实现”和“封装变化的内容”。 基本上,到目前为止,我学到的大多数模式都主要用于使设计能够松散耦合,从而更加灵活。 我了解松耦合的重要性和好处。 但是我的问题是,一个人应该实际投入多少精力来创建松耦合,灵活的设计? 那些反对设计模式的人说,使用这些模式的成本通常会超过收益。您需要花费大量时间来使用某种模式来创建松耦合的设计,而实际上-松耦合,“编程到接口而不是实现”以及所有这些原理实际上可能并不那么重要。 我想知道的是,我实际上应该在创建附加级别的抽象和设计上付出多少努力,才允许我的应用程序遵循OO原则,例如松散耦合,接口编程等,这真的值得吗?它?我应该为此付出多少努力?

4
哪种设计模式更适合记录?
我应该在程序中记录一些事件,但据我所知,最好将记录代码保留在程序之外,因为这与程序的实际功能无关。因此,您能否告诉我是否应该完全将其保留在代码之外,而仅使用观察者和侦听器记录事件?或者,我可以在需要记录某些内容的地方添加如下代码: MyGloriousLogger.getXXXLogger().Log(LogPlace, new LogObject(z1, z2, z3, z4, ..., z99)); 使用观察者设计模式是否会出错?我需要其他设计模式吗?还是我应该停止考虑设计模式? PS1。如果我只想使用侦听器和观察者进行登录,则肯定需要添加和改进程序的观察者和侦听器。 PS2。我当然知道有许多用于登录Java的库,并且我正在使用java.utils.logging,但是我需要有一个包装器来记录我的特殊对象。

2
在哪里验证依赖于数据库内容的域模型规则?
我正在使用允许管理员定义包含字段的表单的系统。然后,使用定义的表格将数据输入系统。有时,表单是由用户通过GUI填写的,有时,表单是根据另一个系统报告的值来填写的。 对于每个字段,管理员可以定义一个验证规则,以限制该字段的允许值。验证规则可以是“在字段中输入的值必须为True或False”到“在字段中输入的值必须存在于数据库表B的A列中”的任何内容。管理员可以随时更改字段的验证规则。 在这种情况下,您认为最适合验证每个字段正确填写的位置是什么?我目前有两种主要方法: 选项1:在域模型中验证 每个字段对象将包含管理员指定的验证规则。Field对象还将引用IValidator。尝试设置字段的值时,字段会将给定的值和验证规则传递给IValidator。如果给定的值无效,则将在另一个系统的GUI /接口中引发ValidationException并进行适当处理。 优点: 强大的保护功能,防止字段被意外分配违反验证规则的值 缺点: 数据访问层需要能够绕过验证并构造违反当前验证规则的字段。尽管管理员更改了字段的验证规则,但我们仍然需要能够基于旧数据构造Field对象,例如,当渲染多年前填充的表单时。每当我们存储字段时,都可以通过存储当前的验证规则来解决此问题。 在这种设计中,Field模型通过IValidator间接链接到数据访问层/存储库。服务/存储库的领域模型的注入似乎被普遍令人难以接受的。 选项2:在服务中验证 尝试确保所有尝试设置字段值的尝试都通过可确保验证规则成立的服务。如果违反了验证规则,则抛出ValidationException。 当然,当创建以前一直保存在数据库中的字段对象时,数据访问层将不会使用服务。 优点: 不违反“不要将服务/存储库注入您的域模型”的思想。 保留字段时,无需保留当前的验证规则。该服务可以简单地查询该字段的当前验证规则;查看历史记录数据时,字段的值不会更改。 缺点: 不能保证应该使用服务设置字段值的所有逻辑实际上都这样做。我认为这是一个主要缺点。似乎要做的就是有人写“ thisField.setValue(thatField.getValue())”,并且可能会违反thisField的验证规则,而没有人明智。当数据访问层将要保留字段时,可以通过确保字段的值与验证规则匹配来缓解这种情况。 我目前更喜欢选项#1,而不是选项#2,主要是因为我将其视为业务逻辑,并认为选项2带来了将不良数据引入系统的更大风险。您更喜欢哪个选项,或者是否有比上述两个选项更适合这种情况的设计? 编辑(验证的复杂性) 目前出现的验证案例相对简单。字段值必须是例如数字,日期,带时间的日期,或者是数据库列中的现有值。但是,我怀疑复杂性会随着时间逐渐增加。例如,验证解决方案的构建必须考虑国际化-诸如Date之类的内容可能会以特定于语言环境的语法输入。 我现在决定继续使用选项#1,尝试注意不要为域模型分配太多职责。那些面临类似情况的人可能还想查看相关问题分层体系结构中的验证和授权以及数据输入验证-在哪里?多少?。

2
策略模式中的上下文类
我试图理解策略模式并问自己:上下文类是必须具备的,还是可以在不损害模式目的的情况下将其省略? 我给我的印象是我需要某种开关来读取不同类型的文件,但不想仅仅破解某些东西,以后再进行重构(尽管当然总是可以对代码进行重构,但是想法是:尝试事先在设计中尽可能地聪明...): 图片取自Wikimedia 客户可以直接委派给Strategy界面吗?或者我只是想了解有关上下文类的内容? interface Reader { // read information from file and fill data list field of Client readFile(); } class ExcelReader implements Reader{ /* */ } class PdfReader implements Reader{ /* */} class Client{ // strategic choice Reader r; // data list field List<Data> data; // Client Constructor …

5
在MVC中,是否可以/应该在View中完成从模型的基本数据检索?
考虑到“瘦控制器,胖模型”的概念以及视图在需要输出数据时视图可以直接调用模型的普遍接受性,是否应该考虑处理视图中请求的“获取和显示”部分而不是控制器?例如(试图使代码相当通用): 控制者 <?php class Invoice extends Base_Controller { /** * Get all the invoices for this month */ public function current_month() { // as there's no user input let's keep the controller very skinny, // DON'T get data from the Model here, just load the view $this->load->view('invoice/current_month'); } } 视图 …


1
在Android上使用FragmentManager的有用设计模式
在处理片段时,我一直在使用由静态方法组成的类,这些方法定义对片段的操作。对于任何给定的项目,我可能都有一个名为的类FragmentActions,其中包含与以下类似的方法: public static void showDeviceFragment(FragmentManager man){ String tag = AllDevicesFragment.getFragmentTag(); AllDevicesFragment fragment = (AllDevicesFragment)man.findFragmentByTag(tag); if(fragment == null){ fragment = new AllDevicesFragment(); } FragmentTransaction t = man.beginTransaction(); t.add(R.id.main_frame, fragment, tag); t.commit(); } 通常每个应用程序屏幕上只有一种方法。当我使用小型本地数据库(通常是SQLite)时,我会执行类似的操作,因此我将其应用于片段,这些片段似乎具有相似的工作流程。我没有嫁给它。 您如何组织应用程序以与Fragments API交互,您认为适用什么设计模式(如果有)?

5
如何对重构为策略模式的功能进行单元测试?
如果我的代码中有一个像这样的函数: class Employee{ public string calculateTax(string name, int salary) { switch (name) { case "Chris": doSomething($salary); case "David": doSomethingDifferent($salary); case "Scott": doOtherThing($salary); } } 通常,我会使用工厂类和策略模式将其重构为使用多态性: public string calculateTax(string name) { InameHandler nameHandler = NameHandlerFactory::getHandler(name); nameHandler->calculateTax($salary); } 现在,如果我正在使用TDD,那么calculateTax()在重构之前,我将对原始版本进行一些测试。 例如: calculateTax_givenChrisSalaryBelowThreshold_Expect111(){} calculateTax_givenChrisSalaryAboveThreshold_Expect111(){} calculateTax_givenDavidSalaryBelowThreshold_Expect222(){} calculateTax_givenDavidSalaryAboveThreshold_Expect222(){} calculateTax_givenScottSalaryBelowThreshold_Expect333(){} calculateTax_givenScottSalaryAboveThreshold_Expect333(){} 重构后,我将具有Factory类NameHandlerFactory和的至少3个实现InameHandler。 我应该如何重构我的测试?我应该claculateTax()从中删除单元测试,EmployeeTests并为的每个实现创建一个Test类InameHandler吗? 我也应该测试工厂课程吗?

4
处理响应的设计模式
大多数时候,当我编写一些代码来处理某个函数调用的响应时,我会得到以下代码结构: 示例:此功能将处理登录系统的身份验证 class Authentication{ function login(){ //This function is called from my Controller $result=$this->authenticate($username,$password); if($result=='wrong password'){ //increase the login trials counter //send mail to admin //store visitor ip }else if($result=='wrong username'){ //increase the login trials counter //do other stuff }else if($result=='login trials exceeded') //do some stuff }else if($result=='banned ip'){ //do …


4
精巧的编程,好的/坏的设计方法
我最近发现了识字编程的概念。我觉得这很有趣。但是我还没有遇到过声称这是构造程序的一种坏方法的说法。似乎没有覆盖很多地方。我什至在这里都找不到任何与此有关的问题。 我的问题不是关于它的缺陷或处理文档的方法。我认为文档对识字编程流程的影响是副作用。我知道设计本来是为了易于文档编制以及正向编程流程的概念。 将问题分为基于小句子的问题的想法似乎确实是一个绝妙的主意。因此,它将简化对程序流程的理解。 素养的设计方法的结果还在于,所需功能的数量将受限于程序员的想象力。代替为特定任务定义功能的方法,可以scrap在识字方法中将其创建为。这将产生代码的自动插入,而不是单独的函数编译,并且随后需要过程间编译优化步骤来获得等效速度。实际上,由于这个事实,唐纳德·E·克努斯(Donald E. Knuth)的第一次尝试执行时间较差。我知道编译器可以解决很多问题,但这不是我关心的问题。 因此,我想获得为什么应该认为这是一种不好/好的设计方法的反馈?

3
观察者模式;知道*什么*改变了吗?
我创建了两个抽象类Subject和Observer,它们定义了经典的Observer模式接口。我从中派生出实现Observer模式的方法。观察者可能看起来像这样: void MyClass::Update(Subject *subject) { if(subject == myService_) { DoSomething(); } else if(subject == myOtherService_) { DoSomethingElse(); } } 很好,它告诉我谁更改了某些内容。但是,它没有告诉我发生了什么变化。有时这是可以的,因为我只是要查询主题以获取最新数据,但是其他时候我需要知道主题上发生了什么变化。我注意到在Java中,它们同时具有notifyObservers()方法和notifyObservers(Object arg)方法,以大概指定有关更改内容的详细信息。 就我而言,我需要知道是否有几个不同的动作中的一个发生在主体上,如果是特定动作,则需要知道与该动作相关的整数。 所以我的问题是: 传递通用参数的C ++方法是什么(就像Java一样)? 观察者甚至是最好的模式吗?也许某种事件系统? 更新 我找到了这篇文章,该文章讨论了如何对观察者模式进行模板化:使用模板实现主题/观察者模式。这让我想知道是否可以模板化参数。 我发现了这个关于模板参数模板化的堆栈溢出问题:基于模板的主题观察者模式-我应该使用static_cast还是dynamic_cast。但是,OP似乎有一个没有人回答的问题。 我可以做的另一件事是将Update方法更改为采用EventArg对象,如下所示: void MyClass::Update(Subject *subject, EventArg arg) { ... 然后为特定的参数数据创建EventArg的子类,然后将其投射回update方法中的特定子类。 更新2 还发现了一篇关于创建基于异步消息的c ++框架的文章;第2部分将具有主题讨论交流有关细节什么改变。 我现在正在认真考虑使用Boost.Signals。简单的时候使用我自己的观察者模式很有意义,但是模板化类型和参数开始变得复杂。我可能需要Boost.Signals2的线程安全性。 更新3 我还发现了一些关于观察者模式的有趣文章: 赫伯·萨特的观察家概论 在C ++中实现观察者模式-第1部分 实施观察者设计模式的经验(第2部分) 实施观察者设计模式的经验(第3部分) 但是,我已将实现切换为使用Boost.Signals,尽管出于我的目的可能有点blo肿,但它可以成功运行。可能有关膨胀或速度的任何问题都是无关紧要的。


2
哪些GOF设计模式已作为C#中的一流语言功能实现?
(由于“太宽泛”和“不是一个真正的问题”,这个问题在Stack Overflow上已经关闭,也许在这里更合适?) 受到这个问题的启发。我们知道事件是Observer模式的语言级实现。是否在C#中将其他设计模式实现为语言功能?我想保留此问题特定于C#,因为有许多其他语言实现的设计模式,并且我想保持专注。 我不是在BCL中寻找模式实现(例如,许多WCF类中的装饰器或中的Factory Method WebClient),而是语言级别的模式。 到目前为止,我知道观察者(event)和迭代器(foreach结合了许多BCL类和接口)。我可能还缺少其他明显的东西。

9
您应该如何向软件世界以外的人解释设计模式
我想向侄女解释设计模式,但是总是很难做到。这在很大程度上是由于我对设计模式缺乏清晰的了解。您如何建议以简单的术语来解释MVC,Singleton,Factory,Repository等模式,即使10岁的孩子也能理解。 我正在寻找可以简化理解模式的示例。例如玩具,电影,音乐等。

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.