浅谈设计模式的六大原则

转发请注明出处: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();

	}
}

Dog类:

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表,类型为Foot
		for(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();
}

Dog类:

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);
	}
}

输出结果:

猫正在移动
猫正在睡觉
猫正在休息
狗正在吃饭
狗正在移动
狗正在睡觉
时间: 2024-10-13 15:28:19

浅谈设计模式的六大原则的相关文章

浅谈设计模式的学习(中)

在<浅谈设计模式的学习(上)>中我说到了设计模式的基石-----抽象思维.为什么需要抽象思维呢?因为越抽象就越不容易出错,就像有些领导人说话:坚持改革开放.但怎么算坚持改革开放呢,没有具体的标准,因事而异,所以就不容易违背这个坚持改革开放的原则了. 3.学习设计模式,要保持抽象的思维     什么是抽象思维呢?真的不好说,抽象的东西往往难以说明白,听了也难以搞明白,还是通过具体的例子来说吧 有这么一个学生请假的场景,如果请假时间一天以内则有班长批准就可以了,三天以内则需要老师批准,超过三天就得

浅谈设计模式1-策略模式

对于大多数面向对象的初学者来说,将思维模式从面向过程转变过来是一个比较困难的过程.很多人在用面向对象语言编写程序的时候,依然会感觉自己在用面向过程的思维,笔者分享这篇文章的用意便是希望可以对大家有一些积极的影响. 阅读本文可以是没有接触设计模式,但需要一定的面向对象基础,至少简单理解封装,继承多态. 对于刚开始接触设计模式来说,一开始就说概念性的东西,很少能够理解.所以我们可以先跳过这些,通过一个小的程序场景来进行一个比较直观的认识. 模拟魂斗罗发射子&弹 相信大家小的时候玩过一款叫魂斗罗的游戏

浅谈设计模式的学习(上)

作为一个开发人员,能写出一个漂亮可扩展的代码,绝对是一件令人愉快的事情.那设计模式就是一门必修课! 本文就自己学习设计模式的一点经历做一个记录. 本人在读大学时,为了学习设计模式就买了一本<java与模式>的数据,书籍有一千多页很重.而且价格不菲.没办法,花那么多钱买的不看岂不浪费.于是每天早上读一章,坚持几个月我终于读完了.这几个月真是煎熬啊,几个月下来,回忆一下似乎自己真得也没收获到什么,很悍然啊.难道是书籍不好吗还是我读的不认真?其实在我现在看来都不是.而为什么读完了却什么也没收获到呢?

设计模式的六大原则

设计模式六大原则(1):单一职责原则 定义:不要存在多于一个导致类变更的原因.通俗的说,即一个类只负责一项职责. 问题由来:类T负责两个不同的职责:职责P1,职责P2.当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障. 解决方案:遵循单一职责原则.分别建立两个类T1.T2,使T1完成职责P1功能,T2完成职责P2功能.这样,当修改类T1时,不会使职责P2发生故障风险:同理,当修改T2时,也不会使职责P1发生故障风险. 说到单一职责原则,很多人都会不屑一顾

设计模式之六大原则(转载)

关于设计模式的六大设计原则的资料网上很多,但是很多地方解释地都太过于笼统化,我也找了很多资料来看,发现CSDN上有几篇关于设计模式的六大原则讲述的比较通俗易懂,因此转载过来. 原作者博客链接:http://blog.csdn.net/LoveLion/article/category/738450/7 一.单一职责原则 原文链接:http://blog.csdn.net/lovelion/article/details/7536542 单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大

浅谈设计模式的学习(下)

时间过得真快啊,不知不觉又要周末了,借这个周末时间.把<浅谈设计模式的学习(下)>补上吧. 在<浅谈设计模式的学习(中)>中,说到了保持抽象的思维.接下来说一下第四点,做一个分享,也记录一下自己的学习历程. 4.学习设计模式,就不要把它看的太认真    设计模式是一个编程思想,它不是具体的代码套路.举个例子说明一下: 由于家传,接触到了一些中国的传统武术.当我与那些不懂传统武术的人交流的时候,他们总是认为中国的传统武术都是些套路.花架子,只是用来好看.在他们认为,两人打架,别人出拳

要想富先练功,设计模式之六大原则

设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设计经验的总结. 使用设计模式的目的:为了代码可重用性.让代码更容易被他人理解.保证代码可靠性. 设计模式使代码编写真正工程化:设计模式是软件工程的基石脉络,如同大厦的结构一样. 设计模式的六大原则是,开发人员必须要掌握的,在开发过程中遵循这些原则,将极大地提升我们的代码质量和开发效率. 下面我们简单回忆一下,这六大原则.如果您没接触过设计模式,那么强烈建议您学习下相关知识. 单一职责:一个类只负责一项职责

浅谈设计模式3-模板方法模式

模版方法模式,个人认为还是用处比较多的一个设计模式,而且也是比较好学和理解的一个.依然来通过模拟一个场景来慢慢了解. 现在我们来实现一下泡茶这个过程.首先我们需要烧开一壶水,然后往茶壶中放茶叶,加入开水,等待茶泡好. 经过前两次的分享,大家应该具备了基本的面向对象的思想了,这里就不再用面向过程的方式演示了. 首先,有一种普通人,他泡茶的方式是这样的 public class Common     { public void MakeTea()         {             Heat

【设计模式的六大原则】

设计模式的六大原则 1.开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭.在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果.所以一句话概括就是:为了使程序的扩展性好,易于维护和升级.想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点. 2.里氏代换原则(Liskov Substitution Principle) 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的