设计模式之单一职责原则

  超前的设计或者过度的设计都不是良好的设计,很多时候我们等到代码在第一次变化的时候可以及时作出反应。

 

  What

  就一个类(接口、结构体、方法等等)而言,应该仅有一个引起它变化的原因。

  Why

  软件设计真正要做的许多内容,就是发现职责并把那些职责互相分离。单一职责原则可以使类的复杂度降低,实现什么职责都有清晰明确的定义;类的可读性提高,复杂度降低(复杂度降低肯定可读性提高);可读性提高了,代码就更容易维护;变更(需求是肯定会变的,程序员都知道)引起的风险(包括测试的难度,以及需要测试的范围)降低。

  How

   需求:实现拍照和播放音乐,那先定义两个功能接口(参照《大话设计模式》)

    //具有照相的功能的接口interface IPhotograph{void Photograph();}
   //具有播放音乐功能的接口interface IPlayMusic{void PlayMusic();}

  不遵循单一原则的设计,播放音乐及拍照功能的改变都会引起变化

  //实现照相、播放音乐的手机类public class MobilePhone : IPhotograph, IPlayMusic{//拍照public void Photograph(){Console.WriteLine("拍照片");}//播放音乐public void PlayMusic(){Console.WriteLine("播放音乐");}}

    

  class Program{static void Main(string[] args){IPlayMusic musicPlayer;IPhotograph photographer;MobilePhone phone = new MobilePhone();musicPlayer = phone;photographer = phone;//播放音乐
            musicPlayer.PlayMusic();//拍照
            photographer.Photograph();Console.ReadLine();}}

 

 

  遵循单一原则的设计,引发改变的只有播放音乐功能的变化

    //实现播放音乐功能的音乐播放器类class MusicPlayer : IPlayMusic{public void PlayMusic(){Console.WriteLine("播放音乐");}}

  遵循单一原则的设计,引发改变的只有摄像功能的变化

    //实现照相功能的摄像机类class Carmera : IPhotograph{public void Photograph(){Console.WriteLine("拍照片");}}

   

class Program{static void Main(string[] args){IPlayMusic musicPlayer;IPhotograph photographer;//MobilePhone phone = new MobilePhone();//musicPlayer = phone;//photographer = phone;
musicPlayer = new MusicPlayer();photographer = new Carmera();//播放音乐
            musicPlayer.PlayMusic();//拍照
            photographer.Photograph();Console.ReadLine();}}

 

 

  糟糕的设计会造成什么样的后果呢?让我们来设想一下,有一天我们的需求发生了变化(需求变化-程序员一生的敌人兼朋友),现有拥有了一部手机,有拍照的功能以及播放音乐的功能,满足了现有的需求,突然有一天觉得简单的拍照功能已经不能满足了,

现在需要能够拍摄高清图片的照相功能,那么怎么办呢?换手机呗,恩找一个支持高清拍照功能的手机。那么好的,需求又变了,现在想要能播放高品质音乐的功能,但是新换的支持高清拍摄的手机的硬件不支持高品质音乐播放,好的,继续换手机,前提是还要

支持拍摄高清照片。相信现在已经能够看出一些端倪了,这两个职责无论哪一个发生了变化,你都要去改变手机,现在只有两个职责,夸张一点说,如果有十个职责呢?那么岂不是要天天换手机,要么就不满足需求变化。

  既然我们看到了糟糕的设计,现在我们回到单一职责上,既然你的需求是拍照片和播放音乐,那么我给你一台相机还有一台音乐播放器,哪个功能需要改变你就换哪个,以后你要换的时候也不必去考虑其他功能,只需要关心引起你自己变化的原因。如果拍照

功能发生改变,我们就去改变照相机,播放音乐功能需要改变我们就去改变音乐播放器。我们不需要去考虑播放高品质音乐是不是会对拍摄高清图片的功能造成影响。

  我们一定要遵循单一职责原则吗?在现有的需求上能做到当然可以去做,但是往往有的时候,需求不是在设计的时候发生改变,而是一定程度之后,你已经有了一定的代码量了,可能修改的开销很高,这个时候就仁者见仁智者见智。就如上述,若是将手机类

拆分,则影响了底层调用的实现,也需要修改,弱是调用的地方太多,那么修改的地方也会很多,若是发布了,改起来也不是很方便,但是当然,也有一定的手法来做这件事情,比如手机类保留,让手机类拥有一个摄像机类对象和一个音乐播放器类对象,然后播放

乐方法则调用音乐播放器类实例的播放音乐功能,照相功能则调用摄像机类实例的照相功能,这样可以在不影响原有的东西的基础上又遵循原则。

转载于:https://www.cnblogs.com/XzcBlog/p/4186081.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/406590.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

makefile常用语法讲解(1)

From: http://www.cnblogs.com/mydomain/archive/2011/08/12/2136083.html 1、make是一个解释makefile中指令的命令工具。Make工具最主要也是最基本的功能就是通过makefile文件来描述源程序之间的相互关系并自动维护编译工作。而makefile 文件需要按照某种语法进行编写&#…

HTML5如何控制暂停播放停止

本篇教程探讨了HTML5如何控制暂停播放停止&#xff0c;希望阅读本篇文章以后大家有所收获&#xff0c;帮助大家HTML5CSS3从入门到精通 。 <!DOCTYPE HTML> <html> <head> <meta charset"utf-8"> <meta name"viewport" content…

Oracle 高水位(HWM: High Water Mark) 说明

一. 准备知识&#xff1a;ORACLE的逻辑存储管理. ORACLE在逻辑存储上分4个粒度: 表空间, 段, 区 和 块. 1.1 块: 是粒度最小的存储单位,现在标准的块大小是8K,ORACLE每一次I/O操作也是按块来操作的,也就是说当ORACLE从数据文件读数据时,是读取多少个块,而不是多少行. 每一个B…

React开发(153):ant design自定义列

<Row gutter{12}><Col span{12}><Form.Item label"省/市/区"><CascaderfieldNames{fieldNames}options{options}onChange{() > {this.onChange();}}placeholder"请输入"/></Form.Item></Col>

[转]那些年我还不懂:IList,ICollection,IEnumerable,IEnumerator,IQueryable

1、首先看一个简单的例子 int[] myArray { 1, 32, 43, 343 };IEnumerator myie myArray.GetEnumerator();myie.Reset();while (myie.MoveNext()){int i (int)myie.Current;Console.WriteLine("Value: {0}", i);} 相信很多人都不会像上面这样去遍历myArray这个数组…

makefile常用讲解(2)

From: http://www.cnblogs.com/mydomain/archive/2011/08/12/2136085.html 4&#xff09;变量的引入 变量的引入和应用&#xff1a; CCgcc HD-I headers SC-c $< OBJ-o $ bin/st_work : obj/main.o obj/st_work.o obj/fun.o gcc $^ -o $ (命令一定要用以Tab…

router-link

组件的属性有&#xff1a; to 、replace、 append、 tag、 active-class、 exact 、 event、 exact-active-class to&#xff08;必选参数&#xff09;&#xff1a;类型string/location 表示目标路由的链接&#xff0c;该值可以是一个字符串&#xff0c;也可以是动态绑定的描…

Qt编程'hello world

#include<QApplication>#include<QLabel>int main(int argc,char*argv[]){QApplicatin app(argc,argv);QLabel *label("hello");label->show();return app.exec()} 编译运行&#xff1a; qmake -project 生成 .pro文件qmake 生成 makemake执行 转载于…

电子工程师必上的十大专业网站

这是很久以前看过的帖子&#xff0c;感觉非常不错&#xff0c;今天特地找出来&#xff0c;便于自己以后经常翻阅&#xff01;&#xff01;今天再看这篇文章&#xff0c;发现很多网站自己还是没有账号&#xff0c;原来自己还是非常的不进取啊。来源&#xff1a;hi.baidu.com 作者…

Makefile文件编写规则

From: http://aviva.iteye.com/blog/807494 Makefile中包含五种内容&#xff1a;显式规则&#xff0c;隐式规则&#xff0c;变量定义&#xff0c;指令&#xff08;directive&#xff09;和注释。 1.显式规则――描述如何生成规则的目标&#xff0c;它列出了目标依赖的文件&…

vue使用better-scroll实现下拉刷新、上拉加载

本文目的是为了实现列表的下拉刷新、上拉加载&#xff0c;所以选择了better-scroll这个库。 用好这个库&#xff0c;需要理解下面说明 必须包含两个大的div&#xff0c;外层和内层div 外层div设置可视的大小(宽或者高)-有限制宽或高 内层div&#xff0c;包裹整个可以滚动的部分…

OpenCV学习 4:摄像头视频读写与边缘检测

原创文章&#xff0c;欢迎转载&#xff0c;转载请注明出处 想实现人脸识别&#xff0c;车辆识别&#xff0c;车牌识别。一般我们可不是读硬盘里面的视频文件的&#xff0c;都是直接从摄像头读取视频流然后直接识别的。所以读取摄像头的视频流这是基础。。。OpenCV对读取摄像头的…

Linux中自带正则表达式应用举例

环境&#xff1a;Fedora12, C程序&#xff1a; #include <stdio.h> #include <string.h> #include <sys/types.h> #include <regex.h>// 提取子串 char* getsubstr(char *s, regmatch_t *pmatch) {static char buf[100] {0};memset(buf, 0, sizeof(b…

ISAPI_Rewrite 规则说明

I (ignore case&#xff09;不管大小写强行指定字符匹配例&#xff1a;RewriteRule /code/project/([0-9,a-z]*).html /soft.jsp\?softpy$1 [I]其他的参数一览I (ignore case&#xff09;不管大小写强行指定字符匹配&#xff0c;这个FLAG影响RewriteRule指令和相应的RewriteCo…

H5页面唤起指定app或跳转到应用市场

场景1&#xff1a; 在 h5 页面上&#xff0c;不管用户是否安装过该app&#xff0c;都直接跳转到应用市场&#xff0c;让用户从应用市场上打开app。 思路&#xff1a; 这种场景处理比较简单&#xff0c;直接判断判断是android端还是ios端&#xff0c;然后在点击按钮上赋值对应…

MyBatis.Net 学习手记

MyBatis.NET的前身为IBatis&#xff0c;是JAVA版MyBatis在.NET平台上的翻版&#xff0c;相对NHibernate、EntityFramework等重量级ORM框架而言&#xff0c;MyBatis.NET必须由开发人员手动写SQL&#xff0c;相对灵活性更大&#xff0c;更容易保证DB访问的性能&#xff0c;适用开…

Python 使用 UTF-8 编码

From: http://blog.chenlb.com/2010/01/python-use-utf-8.html 一般我喜欢用 utf-8 编码&#xff0c;在 python 怎么使用呢&#xff1f; 1、在 python 源码文件中用 utf-8 文字。一般会报错&#xff0c;如下&#xff1a; File "F:\workspace\psh\src\test.py", line …