设计模式学习 - 六大原则

设计模式的六大原则分别是:单一职责原则、开放封闭原则、里氏替换原则、依赖倒置原则、迪米特原则、接口隔离原则

单一职责原则

现在智能手机发展到今天已经非常强大了,集拍摄、MP3、视频、网络等等一系列工具于一身,给人们的生活带来很大的便捷,一定程度上替代某些产品,把众多功能产品整合于一机的思想是好的,然而在某些功能方面目前还是无法媲美专一功能的产品,比如在拍照摄影方面,还是要用专业的单反设备进行工作;从而说明单一职责的产品有者自己独特的优势

在设计模式中的单一职责原则:就定义一个类而言,应该仅有一个引起它变化的原因。通俗的讲就是不要在一个类中做过多的功能实现。如果一个类承担功能职责过多,会增加代码间耦合性,导致后期维护、扩展极其困难,可能修改一处会破坏多处的代码设计。

开放封闭原则

现在很多互联网公司的上班时间是弹性制度,所谓弹性制度,就是早来早下班,晚来晚下班,或者一个月内考勤允许多少次迟到……一系列灵活措施,然而弹性上班的前提是一个必须保证8个小时工作时间,这是硬性要求,而有些公司对上班多少小时并不是十分看重,看重是每个月的业绩是否能达到目标或者超额完成。从中可以看出工作时长或业务成绩在公司一般是不轻易修改关闭的,在达到目标的前提,可以针对时间制度进行变化开放。

在设计模式中的开放封闭原则:面对需求的变化,类、模块、函数等应该都是可以扩展的,但不能轻易被修改。在开发中,往往需求会不断的变化,如果每次变化都要把类重新修改一次,这是一件很头庝的事,此时我们可以通过抽象或接口隔离设计最初功能点,当需求变化的时候,可以用继承的方式重写需要实现的功能。简而言之,就是面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。

里氏替换原则

据野史传说中记载,当年宋哲宗最宠爱的妃子是刘德妃。刘德妃虽然深受皇上宠爱,但是却久久不能生育。刘德妃为竞争皇后之位,提高自己的身价,便想出了“借腹怀孕”的诡计。她打算利用身旁的一个长得有些姿色的姓李的侍女,引诱宋真宗上钩。一次在刘德妃沐浴之时,真宗果真临幸了这个李姓侍女,不久这个侍女就怀孕了,这使刘德妃也装作怀孕的样子,其实侍女怀孕是真,刘德妃只是安排计策假装而已。等到十月分娩的时候,“两个”龙种先后呱呱落地。刘德妃采取了狸猫换太子的卑劣手段,让真宗将李姓侍女打入冷宫,可是自己却如愿以偿地登上了梦寐以求的皇后宝座。

用面向对象的思想可以这样理解:

先创建“父类”– 孕妇,孕妇有两大特征:怀孕、生娃。
然后创建两个孕妇的实例:刘德妃和李姓侍女。
最后在运行时,用自己替换了真正的孕妇李侍女,成功欺骗了皇上。

之所以能够在运行时动态替换,是因为刘德妃的行为里完全继承了孕妇的特征。

在设计模式中的里氏替换原则:所有引用基类(父类)的地方必须能透明地使用其子类的对象。在开发中将一个基类对象替换成子类对象,程序是不会产生任何错误和异常。在实现的过程中子类的所有方法必须在父类中声明,或子类必须实现父类中的所有方法,如果一个方法在子类中独自存在,没有在父类中声明,则无法以父类的名义调用该方法。下面通过代码加深里氏替换原则的理解。

public class Test {

	public static void main(String[] args) {
		Test test = new Test();
		LiuFei liuFei = test.new LiuFei();
		LiNv liNv = test.new LiNv();
		//传入的都是Woman的子类,而getChild方法接受的是父类,这就是替换原则
		test.getChild(liuFei);
		test.getChild(liNv);
	}
	
	
	public void getChild(Woman w){
		w.child();
	}

	abstract class Woman {

		// 怀孕
		void pregnancy() {
		};

		// 生孩子
		void child() {
		};

	}

	class LiuFei extends Woman {

		@Override
		void pregnancy() {
			System.out.println("刘德妃假怀孕");
		}

		@Override
		void child() {
			System.out.println("刘德妃假怀孕,不存在生孩子");
		}

	}

	class LiNv extends Woman {
		@Override
		void pregnancy() {
			System.out.println("李女真怀孕");
		}

		@Override
		void child() {
			System.out.println("李女生孩子了");
		}
	}

}

依赖倒置原则

想必大家对PC机已经很了解了,基本每天都在使用。PC机的组装就是一个典型模块组件的应用,把每个组件进行分离,不相互依赖;如果其中CUP、主板、内存条、硬盘等某个组件坏了,可以快速替换掉,同时不会其他组件的使用。之所以如此方便,是因为组件间没有任何的细节依赖,都是通过对插式进行连接的,所以PC中每个组件都会开放一个或多个插入式接口供使用者。

在设计模式中的依赖倒置原则:高层模块不应该依赖底层模块,两者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。

在java中,抽象一般是指接口或抽象类,它们不会被实例化;细节就是实现类,实现接口或抽象的方法来实现细节。高层模块就是调用者,低层模块就是具体实现类。模块间的依赖通过抽象发生,同样的实现类间也不能直接发生任何依赖,也需通过接口或者抽象类产生依赖。简单理解就是每个模块或者实现类之间不应该发生依赖,需要通过对插式的方式进行关联,正确方式下图:


迪米特原则

在设计模式中迪米特原则:称之为最少知识原则,就是在类的结构设计上,每一个类都应该尽量降低成员的访问权限,也就是说,一个类包装好自己的private状态,不需要让别的类知道字段或行为就不要公开出来。如果两个类不需彼此之间进行通信,那么两个类就不应该发生直接的相互作用。如果其中一个类需要调用另一个类的某个方法的话,可以通过第三者转发这个调用来降低对象之间的耦合度。总而言之,迪米特原则就是尽量避免的让两个对象间发生相互作用

接口隔离原则

在很多课程辅导中,而对于同一知识点,老师可能也要进行不同的课程设计来满足不同层级的学生,往往会分为基础、进阶知识点。

很多时候我们就会把两个不同级别的实现定义成一个公共的接口,这样省事又简单:

public interface CourseLevel {

	//基础课程1
	void baseCourse1();
	
	//基础课程2
	void baseCourse2();
	
	//进阶课程1
	void advancedCourse1();
	
	//进阶课程2
	void advancedCourse2();

}

按照上面的定义,如果使用过程中,没有进行分类,老师不小心把进阶课程讲给了基础学生,岂不是糟了,基础学生能听得懂吗?为了解决上面类似问题,引进了接口隔离原则

在设计模式中接口隔离原则:一个类对另外一个类的依赖应该建立在最小的接口上。感觉好拗口,简单一点就是,建立单一接口,不要建立臃肿庞大的接口。再通俗的一点讲:接口尽量细化,同时接口中的方法尽量的少。我们要为每个类建立专用的接口,而不用试图建立一个庞大而全的接口让类去实现。

针对上面课程的例子,我们按照接口隔离原则进行改进,把基础,进阶课程分为两个不同接口,避免低级问题再次出现。

	public interface BaseCourseLevel{
		
		//基础课程1
		void baseCourse1();
		
		//基础课程2
		void baseCourse2();
	}
	
	public interface AdvancedCourseLevel{
		//进阶课程1
		void advancedCourse1();
		
		//进阶课程2
		void advancedCourse2();
		
	}

单一职责原则与接口隔离原则,两者定义要求分离,但分离的内容是不一样的。

单一职责原则强调是职责,所谓职责就是需求的实现要进行分离,把不同需求封装成不同的模块,没有要求减少接口的方法标准。

接口隔离原则强调是接口单一,尽量为每个类提供专门的接口,就是为不同模块不同功能提供对应的接口,而不是建立庞大的接口。



感谢:

《大话设计模式》、《设计模式之禅》、张拭心之设计模式专栏

猜你喜欢

转载自blog.csdn.net/hzw2017/article/details/80723283