前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >JAVA代码设计六大原则之单一职责

JAVA代码设计六大原则之单一职责

作者头像
用户1205080
发布于 2019-04-25 07:05:01
发布于 2019-04-25 07:05:01
41500
代码可运行
举报
文章被收录于专栏:编码前线编码前线
运行总次数:0
代码可运行

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

Why

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

How

  需求:实现拍照和播放音乐,那先定义两个功能接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //具有照相的功能的接口
    interface IPhotograph
    {
        void Photograph();
    }
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   //具有播放音乐功能的接口
    interface IPlayMusic
    {
        void PlayMusic();
    }

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  //实现照相、播放音乐的手机类
    public class MobilePhone : IPhotograph, IPlayMusic
    {
        //拍照
        public void Photograph()
        {
            Console.WriteLine("拍照片");
        }

        //播放音乐
        public void PlayMusic()
        {
            Console.WriteLine("播放音乐");
        }
    }
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  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();
        }
    }

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //实现播放音乐功能的音乐播放器类
    class MusicPlayer : IPlayMusic
    {
        public void PlayMusic()
        {
            Console.WriteLine("播放音乐");
        }
    }

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //实现照相功能的摄像机类
    class Carmera : IPhotograph
    {
        public void Photograph()
        {
            Console.WriteLine("拍照片");
        }
    }
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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();
        }
    }

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

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

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

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

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

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

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-03-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编码前线 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spark 踩坑记:从 RDD 看集群调度
本文介绍了分布式数据集(RDD)的数学定义和原理,并详细讲解了 Apache Spark 的 RDD 实现。作者通过举例介绍了 RDD 的三种主要转换操作,并探讨了在 Spark 集群环境下,如何通过 RDD 进行分布式计算。最后,本文介绍了在 PySpark 中如何使用 RDD 进行分布式流处理。
肖力涛
2017/08/15
2.3K0
Spark 踩坑记:从 RDD 看集群调度
Spark2.0学习(二)--------RDD详解
添加针对scala文件的编译插件 ------------------------------ <?xml version="1.0" encoding="UTF-8"?> <project xml
大数据流动
2019/08/08
6980
2021年大数据Spark(十四):Spark Core的RDD操作
有一定开发经验的读者应该都使用过多线程,利用多核 CPU 的并行能力来加快运算速率。在开发并行程序时,可以利用类似 Fork/Join 的框架将一个大的任务切分成细小的任务,每个小任务模块之间是相互独立的,可以并行执行,然后将所有小任务的结果汇总起来,得到最终的结果。
Lansonli
2021/10/09
4800
Spark RDD详解 -加米谷大数据
1、RDD是什么 RDD:Spark的核心概念是RDD (resilientdistributed dataset),指的是一个只读的,可分区的分布式数据集,这个数据集的全部或部分可以缓存在内存中,在多次计算间重用。
加米谷大数据
2018/03/21
1.6K3
Spark RDD / Dataset 相关操作及对比汇总笔记
本篇博客将会汇总记录大部分的Spark RDD / Dataset的常用操作以及一些容易混淆的操作对比。
大鹅
2020/10/29
1.7K0
Spark详解02Job 逻辑执行图Job 逻辑执行图
Job 逻辑执行图 General logical plan GeneralLogicalPlan.png 典型的 Job 逻辑执行图如上所示,经过下面四个步骤可以得到最终执行结果: 从数据源(可以是
Albert陈凯
2018/04/08
1.1K0
Spark详解02Job 逻辑执行图Job 逻辑执行图
spark transformation与action操作函数
map(func) 返回一个新的分布式数据集,由每个原元素经过函数处理后的新元素组成
用户3003813
2018/09/06
4750
Apache Spark 2.2.0 中文文档 - Spark 编程指南 | ApacheCN
本文介绍了 Apache Spark 的 RDD 程序设计指南,从 RDD 的基本概念、创建与操作、缓存与存储、性能优化等方面进行了详细阐述,并提供了丰富的实例和代码以帮助读者更好地理解和掌握 RDD 的使用方法。
片刻
2018/01/05
1.7K0
Apache Spark 2.2.0 中文文档 - Spark 编程指南 | ApacheCN
Spark RDD 操作详解——Transformations
Spark RDD 支持2种类型的操作: transformations 和 actions。transformations: 从已经存在的数据集中创建一个新的数据集,如 map。actions: 数据集上进行计算之后返回一个值,如 reduce。
李振
2021/11/26
7890
Transformation 和 Action 常用算子
flatMap(func) 与 map 类似,但每一个输入的 item 会被映射成 0 个或多个输出的 items( func 返回类型需要为 Seq)。
每天进步一点点
2022/07/27
4310
Transformation 和 Action 常用算子
Spark Shell笔记
由外部存储系统的数据集创建,包括本地文件系统,还有Hadoop支持的数据集,如HDFS,HBase
CBeann
2023/12/25
2600
Spark Shell笔记
❤️Spark的关键技术回顾,持续更新!【推荐收藏加关注】❤️
集群环境:CDH版本是5.14.0这个版本 但由于spark对应的5.14.0的CDH版本的软件默认的版本是1.6.0同时阉割了SarkSQL,需要重新编译 原因: 因为Cloudera公司认为有了impala就不需要再使用sparkSQL的功能了,同时也是为了推广impala,所以直接阉割掉了sparkSQL的模块。 解决: 使用Apache的版本的spark来进行重新编译
Lansonli
2021/10/11
5130
Spark开发指南
总的来说,每一个Spark的应用,都是由一个驱动程序(driver program)构成,它运行用户的main函数,在一个集群上执行各种各样的并行操作。Spark提出的最主要抽象概念是弹性分布式数据集 (resilient distributed dataset,RDD),它是元素的集合,划分到集群的各个节点上,可以被并行操作。RDDs的创建可以从HDFS(或者任意其他支持Hadoop文件系统) 上的一个文件开始,或者通过转换驱动程序(driver program)中已存在的Scala集合而来。用户也可以让Spark保留一个RDD在内存中,使其能在并行操作中被有效的重复使用。最后,RDD能自动从节点故障中恢复。
幽鸿
2020/04/02
2K0
Spark计算简单API操作
上面两篇大部分介绍的都是理论知识,希望看到前两篇的都读读。读一遍 不容易理解现在这一篇是介绍api操作的。相对来说容易些也是方便我自己记忆。简单api使用还是特别简单的,如果需要处理的数据量特别的大,那么一定记住api使用调优。 RDD的两种类型操作。 有哪两种操作呢?分别是transformation ,action 也是我们上面所说的转换 和行动。 Transformations 使用的是常用的api操作还有很多可能介绍不到 map():将原来的RDD的每个数据想根据自定义函数进行映射,转换成一个
用户2196435
2018/07/19
6520
Spark入门必读:核心概念介绍及常用RDD操作
导读:Spark是由加州大学伯克利分校AMP实验室开源的分布式大规模数据处理通用引擎,具有高吞吐、低延时、通用易扩展、高容错等特点。Spark内部提供了丰富的开发库,集成了数据分析引擎Spark SQL、图计算框架GraphX、机器学习库MLlib、流计算引擎Spark Streaming。
IT阅读排行榜
2019/05/10
6800
Spark入门必读:核心概念介绍及常用RDD操作
Spark算子官方文档整理收录大全持续更新【Update2023/6/24】
本文基于Spark 3.2.0 Scala的RDD API,内容来源主要由官方文档整理,文中所整理算子为常用收录,并不完全。在Spark RDD官方文档中按照转换算子(Transformation )和行动算子(Action)进行分类,在RDD.scala文档中按照RDD的内部构造进行分类。RDD算子分类方式并不是绝对的,有些算子可能具有多种分类的特征,本文综合两种分类方式便于阅读理解。文中所描述的基本概念来自于官方文档的谷歌翻译和ChatGPT3.5优化,少量来自本人直接翻译。
火之高兴
2024/07/25
1660
Spark action 操作列表
+以下内容来自 Spark 官方文档 Actions 小节, 更多内容可查看官方文档. 如有不当之处, 欢迎指正.
用户1558438
2018/08/23
5850
[大数据之Spark]——Transformations转换入门经典实例
Spark相比于Mapreduce的一大优势就是提供了很多的方法,可以直接使用;另一个优势就是执行速度快,这要得益于DAG的调度,想要理解这个调度规则,还要理解函数之间的依赖关系。 本篇就着重描述
用户1154259
2018/01/17
1.1K0
[大数据之Spark]——Transformations转换入门经典实例
Spark之逻辑处理流程(二)
本文参考许利杰老师的《大数据处理框架Apache Spark设计与实现》,在这里记录一下相关的笔记,补充了一些个人理解,如有不对还请指正。参考链接:https://github.com/JerryLead/SparkInternals
Mirza Zhao
2023/08/24
4910
Spark之逻辑处理流程(二)
BigData--大数据分析引擎Spark
(1)zeroValue:给每一个分区中的每一个key一个初始值; (2)seqOp:函数用于在每一个分区中用初始值逐步迭代value; (3)combOp:函数用于合并每个分区中的结果。
MiChong
2020/09/24
9810
BigData--大数据分析引擎Spark
相关推荐
Spark 踩坑记:从 RDD 看集群调度
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验