浅谈设计模式的六大原则
来源:互联网 发布:vmware安装ubuntu禁用 编辑:程序博客网 时间:2024/06/07 21:10
转发请注明出处:http://blog.csdn.net/qq_28055429/article/details/51507170
一,单一职责原则:就一个类而言,应该仅有一个引起它变化的原因(就是实现类要责任单一)
英文--Single Responsibility Principle
简写:SRP
举个例子:
父类:Animal
public class Animal { void move(String animal){System.out.println(animal + "是主要用脚来移动的");}}
测试类:
<pre name="code" class="java">public class SRPTest {public static void main(String[] args) {Animal animal = new Animal();animal.move("狗");animal.move("猫");animal.move("老鼠");}}输出:
狗是主要用脚来移动的猫是主要用脚来移动的老鼠是主要用脚来移动的那么问题来了,当你添加鸟时,打印出,鸟主要是用脚来移动的,(但好像是翅膀,这里假设为翅膀)
这时,需要改代码了:
如果这样改:
public class Animal { void move(String animal){if("鸟".equals(animal)){System.out.println(animal + "是主要靠翅膀来移动的");}else{System.out.println(animal + "是主要用脚来移动的");}}}没错,可以真确输出,但违背了单一职责原则,假如又要分为类似于猫头鹰等主要靠翅膀在夜间移动的鸟,和靠翅膀在白天移动的鸟,又该如何呢,,,再分呢?
这个时候就要考虑单一职责原则了:
第一种:好像有点违背,但在方法上又好像不违背:
public class Animal { void move(String animal){System.out.println(animal + "是主要靠翅膀来移动的");} void moveN(String animal){System.out.println(animal + "是主要用翅膀来移动的");} }
用两个类,即一个类管理一个原则:
public class Animal { void move(String animal){System.out.println(animal + "是主要靠翅膀来移动的");}}
public class Birds {void move(String animal) {System.out.println(animal + "是主要靠翅膀来移动的");}}测试类:
public class SRPTest {public static void main(String[] args) {Animal animal = new Animal();animal.move("狗");animal.move("猫");animal.move("老鼠");Birds birds = new Birds();birds.move("鸟");}}
二,开放封闭原则:对扩展---开发 , 对更改----封闭
英文:OpenClosePrinciple
简写:OCP
就是说:不要更改源代码(现有代码),而应该增加一个新的类(如子类等)
如版本更新等
版本更新:尽量不更改源代码,可以增加新功能
员工迟到问题:可以制定迟到的晚下班,迟到多久就得加班多久等制度
即:上班总时长封闭,对于迟到一点开放
三,里氏代换原则:子代父,程序行为不变化(有点类似于继承)
英文:Liskov Substitution Principle
简写:LSP
理解:子类必须能够替换他们的父类型,使得父类模块在不改变的情况下,自己可以用扩展性
如 动物,
子:狗,猫,牛
又如一个四则运算的例子:
求加法:
package testtwo;public class Console {int addNumber(int a , int b){return (a + b);}}
测试类:
package testtwo;public class Test {public static void main(String[] args) {Console console = new Console();int result = console.addNumber(8, 2);System.out.println("结果是: " + result);}}
输出结果:
结果是: 10
假如要先求加法再乘法呢,如 (8 + 2)* 4
那么你可能说我直接在Console更改就行啦,但万一,你有好多个类使用了Console的例子呢,那么容易出错,
于是可以新建类来继承,Console不变,
如代码:
package testtwo;public class AConsonle extends Console{int addNumber(int a , int b){return (a + b);}int mulNumber(int a , int b){return (a * b);}}
测试类:
package testtwo;public class Test {public static void main(String[] args) {AConsonle aConsole = new AConsonle();int c = aConsole.addNumber(8, 2);int result = aConsole.mulNumber(c, 4);System.out.println("输出结果是:" + result);}}
输出:
输出结果是:40
四:依赖倒转(置)原则:
英文:Dependence Inversion Principle,
简称 DIP
理解:
(1)抽象不应该依赖细节,细节应该依赖于抽象
(针对接口编程,不要针对现实编程)
(2)高层模块不应该依赖底层模块,两个都应该依赖抽象
抽象:指接口或者抽象类
例子1:假如高层要访问数据库,这时,习惯性的我们喜欢写一个类来实现访问数据库的操作(低层),
即 高层-------底层--------》数据库
但这时,突然客户要求可以根据自己爱好选择不同的存储方式呢,又该如何呢?
例子2:通过代码例子,
package threetest;public class Dog {public void eat(){System.out.println("狗正在吃饭!");}}
动物类:
public class Animal {public void animal (Dog dog){dog.eat();}}测试类:
<pre name="code" class="java">package threetest;public class Test {public static void main(String[] args){Animal a = new Animal();Dog dog = new Dog();a.animal(dog);a.animal(dog);a.animal(dog);}}
输出结果:
狗正在吃饭!狗正在吃饭!狗正在吃饭!
那么这个时候,突然想在测试类,再增加猫正在吃饭,该如何改呢?(增加老鼠呢、、、?)
那么就该想到,依赖抽象,这里以接口为例:
代码:
接口类Ieat:
package threetest;public interface Ieat {public void eat();}
狗类:
package threetest;public class Dog implements Ieat{public void eat(){System.out.println("狗正在吃饭!");}}
猫类:
package threetest;public class Cat implements Ieat{public void eat(){System.out.println("猫正在吃饭!");}}
高层类:
package threetest;public class Animal {public void animal(Ieat ieat){ieat.eat();}}
测试类:
package threetest;public class Test {public static void main(String[] args){Animal a = new Animal();Dog dog = new Dog();Cat cat = new Cat();a.animal(dog);a.animal(dog);a.animal(dog);a.animal(cat);a.animal(cat);a.animal(cat);}}
输出结果:
狗正在吃饭!狗正在吃饭!狗正在吃饭!猫正在吃饭!猫正在吃饭!猫正在吃饭!
由此可见:高层类Animal依赖于抽象(这里是接口)
底层类 :Cat , Dog 也依赖于抽象(这里是接口)
五,迪米特法则:降低类之间的耦合
英文(Law of Demeter,LoD)也称为最少知识原则(Least Knowledge Principle,LKP)
根本思想:是强调了类之间的松耦合,
.....类对自己依赖的类知道的越少越好
......与直接朋友交流
直接朋友包括:
1)当前对象本身(this)
2)以参量形式传入到当前对象方法中的对象
3)当前对象的实例变量直接引用的对象
4)当前对象的实例变量如果是一个聚集,那么聚集中的元素也都是朋友
5)当前对象所创建的对象
任何一个对象,如果满足上面的条件之一,就是当前对象的"朋友";否则就是"陌生人"。
也可以说:
出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。
例子:
Animal类:Dog类属于直接朋友类,因为它是通过方法的输入输出参数成为朋友的,当Foot在方法体count内,不属于直接朋友
方法属于类的行为,一个类竟然不知道他的行为与其他类有依赖关系,这就违反了迪米特法则。
package fourtest;import java.util.ArrayList;import java.util.List;public class Animal {public void count(Dog dog) {List<Foot> list = new ArrayList<Foot>();for(int i = 0 ; i < 10 ; i++){list.add(new Foot());}dog.countFoot(list);}}
</pre><pre name="code" class="java">Dog类:
</pre><pre name="code" class="java"><pre name="code" class="java">package fourtest;import java.util.List;public class Dog {void countFoot(List list){System.out.println("脚共有 :" + list.size() + "只");}}Foot类:这里不写代码
package fourtest;public class Foot {}
测试类:
package fourtest;public class Test {public static void main(String[] args){Animal al = new Animal();Dog dog = new Dog();al.count(dog);}}
输出:
脚共有 :10只没错,结果没错,但却违背了迪米特法则。
应该改为:
Animal类:
package fourtest;import java.util.ArrayList;import java.util.List;public class Animal {public void count(Dog dog) {dog.countFoot();}}
package fourtest;import java.util.ArrayList;import java.util.List;public class Dog {public List<Foot> list ;public Dog(List<Foot> footList){this.list = footList;}void countFoot(){System.out.println("脚共有 :" + list.size() + "只");}}Foot类不变,还是没代码:
Test类:
package fourtest;import java.util.ArrayList;import java.util.List;public class Test {public static void main(String[] args){List<Foot> list = new ArrayList<Foot>();//创建一个List表,类型为Footfor(int i = 0 ; i < 10 ; i++){//存放数据list.add(new Foot());}Dog dog = new Dog(list);//创建Dog对象,list作为参数Animal al = new Animal();//创建Animal对象al.count(dog);//调用Animal对象的count方法,dog作为对象}}输出:
脚共有 :10只
又如图片:
发现每个控件都与其他控件有关系,这样如若修改一个控件,则可能会带动其他控件,
如若用迪米特法则则可以改为:增加一个中介(中间类)来管理,如下:
六,接口隔离原则:
英文:Interface Segregation Principle
简写:ISP
客户端不应该依赖它不需要的接口,一个类对一个类的依赖应该建立在最小的接口上
注意:
(1)接口尽量小,但是要有限度。
(2)为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。
(3)提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
举个例子:
Animal接口:
package fivetest;interface Animal {public void eat();public void move();public void sleep();public void relax();}类Dog:
package fivetest;public class Dog implements Animal{//不是abstract,需重写//我们重写前面三个方法public void eat() {System.out.println("狗正在吃饭");}public void move() {System.out.println("狗正在移动");}public void sleep() {System.out.println("狗正在睡觉");}public void relax() {}}
Cat类:
package fivetest;public class Cat implements Animal{public void eat() {}//这里重写后三个方法public void move() {System.out.println("猫正在移动");}public void sleep() {System.out.println("猫正在睡觉");}public void relax() {System.out.println("猫正在休息");}}
Danimal类:
package fivetest;public class Danimal {public void a1(Animal animal){ animal.eat();}public void a2(Animal animal){animal.move();}public void a3(Animal animal){animal.sleep();}}
Canimal类:
package fivetest; class Canimal {public void b2(Animal animal){animal.move();}public void b3(Animal animal){animal.sleep();}public void b4(Animal animal){ animal.relax();}}测试类:Test
package fivetest;public class Test {public static void main(String[] args){Canimal c = new Canimal();Cat cat = new Cat();c.b2(cat);c.b3(cat);c.b4(cat);Danimal d = new Danimal();Dog dog = new Dog();d.a1(dog);d.a2(dog);d.a3(dog);}}输出结果:
猫正在移动猫正在睡觉猫正在休息狗正在吃饭狗正在移动狗正在睡觉利用迪米特法则改后代码为:
接口:4个:
public interface Eat {public void eat();}public interface Move {public void move();}public interface Sleep {public void sleep();}public interface Relax {public void relax();}
public class Dog implements Eat , Move , Sleep{//我们重写前面三个方法public void eat() {System.out.println("狗正在吃饭");}public void move() {System.out.println("狗正在移动");}public void sleep() {System.out.println("狗正在睡觉");}}
Cat类:
public class Cat implements Move , Sleep , Relax{//这里重写后三个方法public void move() {System.out.println("猫正在移动");}public void sleep() {System.out.println("猫正在睡觉");}public void relax() {System.out.println("猫正在休息");}}Danimal类:
public class Danimal {public void a1(Eat e){ e.eat();}public void a2(Move m){m.move();}public void a3(Sleep s){s.sleep();}}
Canimal类:
class Canimal {public void b2(Move m){m.move();}public void b3(Sleep s){s.sleep();}public void b4(Relax r){ r.relax();}}
测试类:
public class Test {public static void main(String[] args){Canimal c = new Canimal();Cat cat = new Cat();c.b2(cat);c.b3(cat);c.b4(cat);Danimal d = new Danimal();Dog dog = new Dog();d.a1(dog);d.a2(dog);d.a3(dog);}}
输出结果:
猫正在移动猫正在睡觉猫正在休息狗正在吃饭狗正在移动狗正在睡觉
- 浅谈设计模式的六大原则
- 浅谈设计模式六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- 设计模式的六大原则
- FLEX个人学习点滴
- (andorid硬件应用实战)利用底层api camera实现摄像头拍照功能总结
- PostgreSQL的执行计划分析
- VLC搭建RTSP服务器的过程
- iOS开发UI篇—popoverController使用注意
- 浅谈设计模式的六大原则
- 第一次在阿里云服务器部署javaWeb工程
- Mybatis极其(最)简(好)单(用)的一个分页插件
- 给你的网站或平台设置一个icon
- iOS学习之——Container View Controller
- display:flex 布局教程
- Android 释放资源和进程的优先级顺序
- 深入学习:Windows下Git入门教程(上)
- Linux(Centos)下Redis开机自启设置