目录
面向对象,六大原则,设计模式,数据结构与算法,这些知识点都是脱离编程语言存在的。也就意味着它们 “比较抽象”,抽象的东西也就意味着从学习、理解到运用所需要花费的时间会比较长。
今天我们就主要谈谈设计模式的“六大原则”。
它们分别是单一职责、开闭原则原则、依赖倒置原则、里氏替换原则、接口隔离原则、迪米特原则。
六大原则是我们提高面向对象编程代码质量的必备原则,另外还是我们理解设计模式的必备前提。
弄清楚了学习对象和学习目的,下面就可以进入正题了,这六大设计原则本质上是什么,又分别是用来做什么的,实际中的运用又有哪些?
定义:就一个类而言,应该仅有一个引起它变化的原因。简单点理解就是,就是一个类只负责一项职责(功能)。
从生活中的具体示例理解单一职责:
冰淇淋:单一职责是被吃
矿泉水:单一职责是被饮用
ofo:单一职责是共享单车
生活中的事物的单一性是为了集中(精力 / 财力 / 物力),然后把这一点做到最好,只有这样才能更有竞争力。
而编程中的单一性也是为了集中,一个类它的功能,作用,用途集中到一点。这样可以避免代码冗余,方便管理,方便团队沟通,能提高项目的开发效率。
public interface UserService {
public void login(String username, String password);
public void register(String email, String username, String password);
public void logError(String msg);
public void sendEmail(String email);
}
这段代码很显然存在很大的问题,UserService 既要负责用户的注册和登录,还要负责日志的记录和邮件的发送,并且后者的行为明显区别于前者。
假设我要修改发送邮件的逻辑就得修改这个类,这时候 qa 还得回归登录注册逻辑,这样明显不合理。
UserService:只负责登录注册
public interface UserService {
public void login(String username, String password);
public void register(String email, String username, String password);
}
LogService :只负责日志
public interface LogService {
public void logError(String msg);
}
EmailService: 只负责发送邮件
public interface EmailService {
public void sendEmail(String email);
}
结合 Unity 项目开发过程中,有两个注意点:
①类功能的单一性;
②方法功能的单一性;
一个类只负责一件具体的事情,一个方法只完成一个特定的功能。当你发现一方法完成了两件事情的时候,就需要适当的重构成两个方法,类也是一样的。单一职责在 unity 项目开发中的应用:
①功能类库的单一性:例如 UGUI 中的 JSON 就是单一用于解析 JSON 的。
②引擎组件类功能单一性:在 Unity 引擎内有一组灯光组件,是用于实现灯光照射渲染功能的。它根不同的功能分割成了 4 个组件:方向光,点光源,聚光灯,区域光。
定义:全称开放封闭原则,软件实体(类,方法,模块)应该可以扩展,但是不可以修改。
在生活中的具体应用:
笔记本电脑
封闭:整个笔记本是封闭的,且笔记本背部标明了 “非专业人士,请勿试图拆卸或者维修” 以及 “撕毁保修无效” 的封条。
开放:指的是笔记本提供了若干个 USB 的插口,可供我们扩展。
笔记本上的封闭,是为了保证设备本身的安全。而笔记本上的开放,是为用户预留可以扩展的接口。
而编程中的封闭,也是为了保证原有的安全,当出现了新的需求,是以扩展的方式,而不是对原有的逻辑进行修改。面对需求,对程序的改动应该是以增加新代码的方式解决,而不是更改旧的代码 (这一点在游戏开发方向尤为重要)。
Unity 引擎本身就是开闭原则很好的一个案例。
Unity 官方把这款引擎打包发布出来以后,这个引擎本身程序员是不可以修改的,因为你没有源码 ---> 对修改关闭。但是 Unity 引擎提供了 “编辑器扩展功能”,提供了一组完整的 API,我们可以通过这组 API 对 Unity 引擎扩展出 N 个插件,以满足我们的特定需求。
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI