白话设计模式六大原则
原文链接: http://www.jianshu.com/p/a489dd5ad1fe
前言
不管你是一个android程序员还是ios,后台程序员,一个好的程序员,不是只会埋头敲代码可以造就的,有时候抬头思考肿么把以后的代码写的更好更有价值。设计模式是一种思考肿么构造代码的方法。今天想结合例子谈谈设计模式的六大基本原则。希望能简单点把问题说清楚,避免高大上的定义,虚无缥缈的遣词造句。
1
单一职责原则
一开始我需要一只会吃吃喝喝的宠物,于是我写了
public class Animal {
public void eat() {
Log.i("", "eat");
}
public void drink() {
Log.i("", "drink");
}
}
一个领养的方法
public class Host {
public void adopt(Dog dog){
Log.i("", "i get dog");
}
}
然后我发现要区分下狗和猫的吃喝,我改
public class Animal {
public void eat(String kind) {
if (kind.equals("cat")) Log.i("", "吃鱼");
if (kind.equals("dog")) Log.i("", "吃骨头");
}
public void drink(String kind) {
if (kind.equals("cat")) Log.i("", "喝鱼汤");
if (kind.equals("dog")) Log.i("", "喝骨头汤");
}
}
最后我发现鸡,鸭,鹅。。。都要加进来,我要写多少if,狗带boy。。。我不如把每种动物各自建个类,各自负责自己的吃喝,来一个加一个岂不是happy。于是默默记住
单一职责原则:不要存在多于一个导致类变更的原因
2
里氏替换原则
于是我新建了一个类Dog继承了开始的时候的Animal,至于为什么要继承。。。来源于直觉。。。animal>dog。。。包含关系不是吗?
public class Dog extends Animal{
public void eat() {
Log.i("", "吃骨头");
}
public void drink() {
Log.i("", "喝骨头汤");
}
}
写完了以后发现有点不对劲,貌似违反了
里氏替换原则:子类可以扩展父类的功能,但不能改变父类原有的功能。
我这样一写如果把用到Animal的地方换成Dog,所有的动物都变成吃骨头了。
3
依赖倒置原则
既然继承不能用了,领养的方法出现了难题,我总不能
public void adopt(Dog dog){
Log.i("", "i get dog");
}
public void adopt(Cat cat){
Log.i("", "i get cat");
}
.....无数鸡,鸭,鹅方法飞过......
要是真这样估计累死。于是,我想到了接口
public interface Animal {
public void eat();
public void drink();
}
public class Dog implements Animal{
public void eat() {
Log.i("", "吃骨头");
}
public void drink() {
Log.i("", "喝骨头汤");
}
}
完美。契合了面向接口编程,而且符合
依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象
领养方法做为高层模块没有直接依赖猫猫狗狗等低层模块,依赖了其抽象,扩展性棒棒的。
4
接口隔离原则
然后发现猫有爬树的技能,狗有汪汪的神级,于是我加了
public interface Animal {
public void eat();
public void drink();
//猫爬树
public void climbTree();
//狗汪汪
public void yell();
}
于是狗变成
public class Dog implements Animal{
public void eat() {
Log.i("", "吃骨头");
}
public void drink() {
Log.i("", "喝骨头汤");
}
@Override
public void climbTree() {
}
@Override
public void yell() {
Log.i("", "汪汪");
}
}
由于狗不会爬树,所以爬树的方法空着。转而一想这样不行,狗还不会飞,不会。。。。等引入其他大量动物,岂不是有大量的空方法?
接口隔离原则:客户端不应该被强迫地依赖那些根本用不上的方法。
我只好把接口拆开,用组合搞定,组合是比较推荐的方式。
public interface Animal {
public void eat();
public void drink();
}
public interface Yell {
//狗汪汪
public void yell();
}
public class Dog implements Animal, Yell{
public void eat() {
Log.i("", "吃骨头");
}
public void drink() {
Log.i("", "喝骨头汤");
}
@Override
public void yell() {
Log.i("", "汪汪");
}
}
这样狗还有其他技能也可以实现其他接口,当然其他动物要是有相同的技能可以实现相同的接口。关键是没有空方法了,哈哈。
5
迪米特原则
防疫站需要每个宠物的信息,这时候需要一个EpidemicStation对象。如何获取宠物信息有2种方式
- 通过宠物的主人,EpidemicStation早已有了Host对象,而Host中有一系列关于宠物(Animal)的方法
- 直接new一个宠物的对象,获取相关信息
我们肯定直接会选择第一种。。。直觉是可以少建个对象。。。早说了我就是这种偷懒的程序猿。。。然而莫名的契合了迪米特法则
迪米特法则:一个对象应该对其他对象保持最少的了解
Host只需要对Animal对象保持关注,而EpidemicStation只需要对Host对象保持关注。EpidemicStation对象不需要了解Animal。感觉直接点就是,在一个类中应该少出现其他类,其实这也是解耦的需要。
6
开闭原则
直接抛出定义吧
开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭
感觉这个原则容易看懂,最难做到。白话就是不要改你以前写的代码,你应该加一些代码去扩展原来的功能,来实现新的需求。好处很好理解,改原来的代码很容易影响原来的功能,特别是接手别人的代码,不理解原先业务场景的情况下。关于‘不要动之前的代码’感觉槽点无数啊,看自己写的代码想吐有木有?别人的代码简直…?之前哪里会想到会有这种鬼需求?…….
后记
绞尽脑汁把原则说清楚。感觉原则性的东西应该是简单易遵守的,重要的还是在以后的编程中实践,所以下手写代码前再看看本文?想想六个原则?如果有用欢迎关注我,欢迎点喜欢。。。
推荐
一个神奇的网站 http://androidcat.com/
特别声明:本文由原作者wolearn原创并授权发布,未经原作者允许请勿转载。转载请联系原作者。
- 干货 | Tomcat类加载机制触发的Too many open files问题分析
- 并行查询缓慢的问题分析(r5笔记第86天)
- Swagger文档转Word 文档
- AJAX应用【股票案例、验证码校验】
- IT中的闰秒问题(r5笔记第85天)
- 浅谈exp/imp(下) (r5笔记第84天)
- 多线程编程学习五(线程池的创建)
- 再学习之Spring(面向切面编程).
- Hybris CronJob
- tomcat源码编译和环境搭建(r5笔记第83天)
- NumPy 将停止支持 Python 2,这里有一份给数据科学家的 Python 3 使用指导
- Apache solr(一).
- dataguard中MRP无法启动的问题分析和解决(r5笔记第82天)
- Apache solr(二).
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【python-leetcode141-快慢指针】环形链表
- python-快速排序
- 【python-leetcode75-双指针】颜色分类
- 【python-leetcode713-双指针】乘积小于k的子数组
- vuejs之构建简易音乐播放器
- vuejs小例子之天气查询
- 【python-leetcode259-双指针】三个数的最小和
- vuejs之vue.js+axios结合使用
- c语言之指向指针的指针
- c语言之利用#if #endif来进行注释或者运行不同的主函数
- c++之对组pair
- c++STL容器之set/multiset容器
- c++STL容器之list容器
- c++STL容器之deque容器
- Web自动化必会「Web基础、元素定位、元素操作、Selenium运行原理、项目实战+框架」