浅谈设计模式的六大原则

转发请注明出处: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 + "是主要用脚来移动的");

}

}
测试类:
public class SRPTest {
 
	public static void main(String[] args) {
		Animal animal = new Animal();
		animal.move("狗");
		animal.move("猫");
		animal.move("老鼠");
 
	}
 }
 
  1. 狗是主要用脚来移动的

  2. 猫是主要用脚来移动的

  3. 老鼠是主要用脚来移动的

那么问题来了,当你添加鸟时,打印出,鸟主要是用脚来移动的,(但好像是翅膀,这里假设为翅膀)

这时,需要改代码了:

如果这样改:

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 + "是主要靠翅膀来移动的");
	}
}

 

测试类:

 

二,开放封闭原则:对扩展---开发 , 对更改----封闭

 

 

英文:OpenClosePrinciple

简写:OCP

就是说:不要更改源代码(现有代码),而应该增加一个新的类(如子类等)

如版本更新等

 

版本更新:尽量不更改源代码,可以增加新功能

员工迟到问题:可以制定迟到的晚下班,迟到多久就得加班多久等制度

即:上班总时长封闭,对于迟到一点开放

 

 

三,里氏代换原则:子代父,程序行为不变化(有点类似于继承)

英文:Liskov Substitution Principle 

简写:LSP

理解:子类必须能够替换他们的父类型,使得父类模块在不改变的情况下,自己可以用扩展性

如  动物,

子:狗,猫,牛

又如一个四则运算的例子:

求加法:

 

 
  1. package testtwo;

  2.  
  3. public class Console {

  4. int addNumber(int a , int b){

  5. return (a + b);

  6. }

  7. }


测试类:

 

 

 
  1. package testtwo;

  2.  
  3. public class Test {

  4.  
  5. public static void main(String[] args) {

  6. Console console = new Console();

  7. int result = console.addNumber(8, 2);

  8. System.out.println("结果是: " + result);

  9. }

  10. }


输出结果:

 

结果是: 10

假如要先求加法再乘法呢,如 (8 + 2)* 4

那么你可能说我直接在Console更改就行啦,但万一,你有好多个类使用了Console的例子呢,那么容易出错,

于是可以新建类来继承,Console不变,

如代码:

 

 
  1. package testtwo;

  2.  
  3. public class AConsonle extends Console{

  4. int addNumber(int a , int b){

  5. return (a + b);

  6. }

  7. int mulNumber(int a , int b){

  8. return (a * b);

  9. }

  10. }


测试类:

 

 

 
  1. package testtwo;

  2.  
  3. public class Test {

  4.  
  5. public static void main(String[] args) {

  6.  
  7. AConsonle aConsole = new AConsonle();

  8. int c = aConsole.addNumber(8, 2);

  9. int result = aConsole.mulNumber(c, 4);

  10. System.out.println("输出结果是:" + result);

  11.  
  12. }

  13. }


输出:

输出结果是:40

 

四:依赖倒转(置)原则:  

英文:Dependence Inversion Principle,

简称 DIP

理解:

(1)抽象不应该依赖细节,细节应该依赖于抽象

    (针对接口编程,不要针对现实编程)

(2)高层模块不应该依赖底层模块,两个都应该依赖抽象

抽象:指接口或者抽象类

 

 

例子1:假如高层要访问数据库,这时,习惯性的我们喜欢写一个类来实现访问数据库的操作(低层),

即   高层-------底层--------》数据库

但这时,突然客户要求可以根据自己爱好选择不同的存储方式呢,又该如何呢?

 

例子2:通过代码例子,

 

 
  1. package threetest;

  2.  
  3. public class Dog {

  4. public void eat(){

  5. System.out.println("狗正在吃饭!");

  6. }

  7.  
  8. }


动物类:

 

 

 
  1. public class Animal {

  2. public void animal (Dog dog){

  3. dog.eat();

  4. }

  5. }

测试类:

 

 

 
  1. <pre name="code" class="java">package threetest;

  2.  
  3. public class Test {

  4. public static void main(String[] args){

  5. Animal a = new Animal();

  6. Dog dog = new Dog();

  7. a.animal(dog);

  8. a.animal(dog);

  9. a.animal(dog);

  10.  
  11. }

  12. }

 

 

 

 

输出结果:

 

狗正在吃饭!狗正在吃饭!狗正在吃饭!

 

那么这个时候,突然想在测试类,再增加猫正在吃饭,该如何改呢?(增加老鼠呢、、、?)

那么就该想到,依赖抽象,这里以接口为例:

代码:

接口类Ieat:

 

 
  1. package threetest;

  2.  
  3. public interface Ieat {

  4. public void eat();

  5. }

 

狗类:

 

 
  1. package threetest;

  2.  
  3. public class Dog implements Ieat{

  4. public void eat(){

  5. System.out.println("狗正在吃饭!");

  6. }

  7.  
  8. }


猫类:

 

 

 
  1. package threetest;

  2.  
  3. public class Cat implements Ieat{

  4. public void eat(){

  5. System.out.println("猫正在吃饭!");

  6. }

  7. }


高层类:

 

 

 
  1. package threetest;

  2.  
  3. public class Animal {

  4. public void animal(Ieat ieat){

  5. ieat.eat();

  6. }

  7. }


测试类:

 

 

 
  1. package threetest;

  2.  
  3. public class Test {

  4. public static void main(String[] args){

  5. Animal a = new Animal();

  6. Dog dog = new Dog();

  7. Cat cat = new Cat();

  8. a.animal(dog);

  9. a.animal(dog);

  10. a.animal(dog);

  11. a.animal(cat);

  12. a.animal(cat);

  13. a.animal(cat);

  14. }

  15. }


输出结果:

 

 

 
  1. 狗正在吃饭!

  2. 狗正在吃饭!

  3. 狗正在吃饭!

  4. 猫正在吃饭!

  5. 猫正在吃饭!

  6. 猫正在吃饭!


由此可见:高层类Animal依赖于抽象(这里是接口)

 

              底层类 :Cat , Dog 也依赖于抽象(这里是接口)
 

五,迪米特法则:降低类之间的耦合

英文(Law of Demeter,LoD)也称为最少知识原则(Least Knowledge Principle,LKP)

根本思想:是强调了类之间的松耦合,

.....类对自己依赖的类知道的越少越好

 ......与直接朋友交流

直接朋友包括:

1)当前对象本身(this)
2)以参量形式传入到当前对象方法中的对象
3)当前对象的实例变量直接引用的对象
4)当前对象的实例变量如果是一个聚集,那么聚集中的元素也都是朋友
5)当前对象所创建的对象
任何一个对象,如果满足上面的条件之一,就是当前对象的"朋友";否则就是"陌生人"。

也可以说:

出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。

 

例子:

Animal类:Dog类属于直接朋友类,因为它是通过方法的输入输出参数成为朋友的,当Foot在方法体count内,不属于直接朋友

方法属于类的行为,一个类竟然不知道他的行为与其他类有依赖关系,这就违反了迪米特法则。

 

 
  1. package fourtest;

  2.  
  3. import java.util.ArrayList;

  4. import java.util.List;

  5.  
  6. public class Animal {

  7. public void count(Dog dog) {

  8. List<Foot> list = new ArrayList<Foot>();

  9. for(int i = 0 ; i < 10 ; i++){

  10. list.add(new Foot());

  11. }

  12. dog.countFoot(list);

  13.  
  14. }

  15. }

</pre><pre name="code" class="java">Dog类:
 
  1. </pre><pre name="code" class="java"><pre name="code" class="java">package fourtest;

  2. import java.util.List;

  3. public class Dog {

  4. void countFoot(List list){

  5. System.out.println("脚共有 :" + list.size() + "只");

  6. }

  7. }

 

 

Foot类:这里不写代码

 

 
  1. package fourtest;

  2. public class Foot {

  3.  
  4. }


测试类:

 

 
  1. package fourtest;

  2. public class Test {

  3. public static void main(String[] args){

  4. Animal al = new Animal();

  5. Dog dog = new Dog();

  6. al.count(dog);

  7. }

  8. }


输出:

 

 

脚共有 :10

没错,结果没错,但却违背了迪米特法则。

应该改为:

Animal类:

 

 
  1. package fourtest;

  2. import java.util.ArrayList;

  3. import java.util.List;

  4. public class Animal {

  5. public void count(Dog dog) {

  6. dog.countFoot();

  7.  
  8. }

  9. }

 

Dog类:

 
  1. package fourtest;

  2. import java.util.ArrayList;

  3. import java.util.List;

  4. public class Dog {

  5. public List<Foot> list ;

  6. public Dog(List<Foot> footList){

  7. this.list = footList;

  8. }

  9. void countFoot(){

  10. System.out.println("脚共有 :" + list.size() + "只");

  11. }

  12. }

Foot类不变,还是没代码:

 

Test类:

 
  1. package fourtest;

  2. import java.util.ArrayList;

  3. import java.util.List;

  4.  
  5. public class Test {

  6. public static void main(String[] args){

  7. List<Foot> list = new ArrayList<Foot>(); //创建一个List表,类型为Foot

  8. for(int i = 0 ; i < 10 ; i++){ //存放数据

  9. list.add(new Foot());

  10. }

  11. Dog dog = new Dog(list); //创建Dog对象,list作为参数

  12. Animal al = new Animal(); //创建Animal对象

  13. al.count(dog); //调用Animal对象的count方法,dog作为对象

  14.  
  15. }

  16. }

输出:

 

 

脚共有 :10

又如图片:

 

发现每个控件都与其他控件有关系,这样如若修改一个控件,则可能会带动其他控件,

如若用迪米特法则则可以改为:增加一个中介(中间类)来管理,如下:

 

 

 

六,接口隔离原则:

 

 

 

英文:Interface Segregation Principle

简写:ISP

客户端不应该依赖它不需要的接口,一个类对一个类的依赖应该建立在最小的接口上

注意:

   (2)为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。
   (3)提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

 

举个例子:

Animal接口:

 

 
  1. package fivetest;

  2. interface Animal {

  3. public void eat();

  4. public void move();

  5. public void sleep();

  6. public void relax();

  7. }

类Dog:

 

 

 
  1. package fivetest;

  2. public class Dog implements Animal{

  3. //不是abstract,需重写

  4. //我们重写前面三个方法

  5. public void eat() {

  6. System.out.println("狗正在吃饭");

  7. }

  8. public void move() {

  9. System.out.println("狗正在移动");

  10. }

  11. public void sleep() {

  12. System.out.println("狗正在睡觉");

  13. }

  14. public void relax() {}

  15. }


Cat类:

 

 

 
  1. package fivetest;

  2. public class Cat implements Animal{

  3. public void eat() {}

  4. //这里重写后三个方法

  5. public void move() {

  6. System.out.println("猫正在移动");

  7. }

  8. public void sleep() {

  9. System.out.println("猫正在睡觉");

  10. }

  11. public void relax() {

  12. System.out.println("猫正在休息");

  13. }

  14. }


Danimal类:

 

 

 
  1. package fivetest;

  2.  
  3. public class Danimal {

  4. public void a1(Animal animal){

  5. animal.eat();

  6. }

  7. public void a2(Animal animal){

  8. animal.move();

  9. }

  10. public void a3(Animal animal){

  11. animal.sleep();

  12. }

  13. }


Canimal类:

 

 

 
  1. package fivetest;

  2.  
  3. class Canimal {

  4. public void b2(Animal animal){

  5. animal.move();

  6. }

  7. public void b3(Animal animal){

  8. animal.sleep();

  9. }

  10. public void b4(Animal animal){

  11. animal.relax();

  12. }

  13. }

测试类:Test

 

 
  1. package fivetest;

  2.  
  3. public class Test {

  4. public static void main(String[] args){

  5.  
  6. Canimal c = new Canimal();

  7. Cat cat = new Cat();

  8. c.b2(cat);

  9. c.b3(cat);

  10. c.b4(cat);

  11.  
  12. Danimal d = new Danimal();

  13. Dog dog = new Dog();

  14. d.a1(dog);

  15. d.a2(dog);

  16. d.a3(dog);

  17. }

  18. }

输出结果:

 

 

 
  1. 猫正在移动

  2. 猫正在睡觉

  3. 猫正在休息

  4. 狗正在吃饭

  5. 狗正在移动

  6. 狗正在睡觉

利用迪米特法则改后代码为:

 

接口:4个:

 

 
  1. public interface Eat {

  2. public void eat();

  3. }

  4.  
  5. public interface Move {

  6. public void move();

  7. }

  8.  
  9. public interface Sleep {

  10. public void sleep();

  11. }

  12.  
  13. public interface Relax {

  14. public void relax();

  15. }

  16.  

 

 

Dog类:

 

 
  1. public class Dog implements Eat , Move , Sleep{

  2. //我们重写前面三个方法

  3. public void eat() {

  4. System.out.println("狗正在吃饭");

  5. }

  6. public void move() {

  7. System.out.println("狗正在移动");

  8. }

  9. public void sleep() {

  10. System.out.println("狗正在睡觉");

  11. }

  12. }


Cat类:

 

 

 
  1. public class Cat implements Move , Sleep , Relax{

  2. //这里重写后三个方法

  3. public void move() {

  4. System.out.println("猫正在移动");

  5. }

  6. public void sleep() {

  7. System.out.println("猫正在睡觉");

  8. }

  9. public void relax() {

  10. System.out.println("猫正在休息");

  11. }

  12. }

Danimal类:

 

 
  1. public class Danimal {

  2. public void a1(Eat e){

  3. e.eat();

  4. }

  5. public void a2(Move m){

  6. m.move();

  7. }

  8. public void a3(Sleep s){

  9. s.sleep();

  10. }

  11. }


Canimal类:

 

 
  1. class Canimal {

  2. public void b2(Move m){

  3. m.move();

  4. }

  5. public void b3(Sleep s){

  6. s.sleep();

  7. }

  8. public void b4(Relax r){

  9. r.relax();

  10. }

  11. }


测试类:

 
  1. public class Test {

  2. public static void main(String[] args){

  3.  
  4. Canimal c = new Canimal();

  5. Cat cat = new Cat();

  6. c.b2(cat);

  7. c.b3(cat);

  8. c.b4(cat);

  9.  
  10. Danimal d = new Danimal();

  11. Dog dog = new Dog();

  12. d.a1(dog);

  13. d.a2(dog);

  14. d.a3(dog);

  15. }

  16. }


输出结果:

 
  1. 猫正在移动

  2. 猫正在睡觉

  3. 猫正在休息

  4. 狗正在吃饭

  5. 狗正在移动

  6. 狗正在睡觉

转载于:https://blog.csdn.net/qq_28055429/article/details/51507170


 

 



 

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值