目录
设计模式的目的
编写软件的过程中,程序员面临着来自耦合性,内聚性,可扩展性,维护性,灵活性。
- 代码重用性:相同的代码不用重写
- 可读性:便于阅读和理解
- 可扩展性:当扩展其他功能的时候方便
- 可靠性:添加新功能时对其他的功能没有影响
- 程序呈现高内聚低耦合的特性
七大原则:
- 单一原则
- 接口原则
- 依赖倒转原则
- 里氏替换原则
- 开闭原则
- 迪米特原则
- 合成复用原则
(1)单一原则
介绍:对类来说,一个类只应该负责一个职责。
实例:
package com.kun.principle.singlersponsibilit;
public class SingleResponsibility1 {
public static void main(String[] args) {
/*
* 一个类(违反了单一原则)——》
* 三个类(使用了单一原则,但是消耗资源)——》
* 一个类三个方法(类上没有体现单一原则,但是方法体现了)
* */
AirVehicle vehicle1=new AirVehicle();
vehicle1.run("feiji");
RoadVehicle vehicle2=new RoadVehicle();
vehicle2.run("qiche");
WaterVehicle vehicle3=new WaterVehicle();
vehicle3.run("zixingche");
}
}
// 交通工具类
class AirVehicle{
public void run(String vehicle) {
System.out.println(vehicle + " zai fei");
}
}
class RoadVehicle{
public void run(String vehicle) {
System.out.println(vehicle + " zai pao");
}
}
class WaterVehicle{
public void run(String vehicle) {
System.out.println(vehicle + " zai you");
}
}
单一职责注意事项和细节
- 降低类的复杂度,一个类只负责一项职责。
- 提高类的可读性,可维护性。
- 降低变更引起的风险。
- 通常情况下,我们应当遵守单一职责原则,除非逻辑足够简单。可以在方法上实现单一职责。
(2)接口隔离原则
介绍:一个类对另一个类的依赖,用接口来依赖,应当依赖最小组合的接口。如(A用B中的1,2,3接口,则应该拆分[1],[2,3])
实例:
package com.kun.principle.segregation;
public class Segregation {
public static void main(String[] args) {
A a=new A();
a.depend1(new B());
}
}
interface Interface1{
void operation1();
void operation2();
void operation3();
void operation4();
void operation5();
}
class B implements Interface1{
@Override
public void operation1() {
System.out.println("B 1");
}
@Override
public void operation2() {
System.out.println("B 2");
}
@Override
public void operation3() {
System.out.println("B 3");
}
@Override
public void operation4() {
System.out.println("B 4");
}
@Override
public void operation5() {
System.out.println("B 5");
}
}
class A {
public void depend1(Interface1 i) {
i.operation1();
i.operation2();
i.operation3();
}
}
改进版
package com.kun.principle.segregation;
public class improve {
public static void main(String[] args) {
}
}
interface inter1{
void operation1();
}
interface inter2{
void operation2();
void operation3();
}
class B implements inter1,inter2{
@Override
public void operation1() {
System.out.println("B 1");
}
@Override
public void operation2() {
System.out.println("B 2");
}
@Override
public void operation3() {
System.out.println("B 3");
}
}
class A {
public void depend1(inter1 i) {
i.operation1();
}
public void depend2(inter2 i) {
i.operation2();
i.operation3();
}
}
(3)依赖倒转原则
介绍:
- 高层模块不应该依赖低层模块,二者都应该依赖其抽象。
- 抽象不应该依赖细节,细节应该依赖抽象。
- 依赖倒转的思想是面向接口编程。
- 依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在java中,抽象指的是接口或抽象类,细节就是具体的实现类
- 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成
实例:
package com.kun.principle.inversion;
public class DependecyInversion {
public static void main(String[] args) {
//客户端无需改变
Person person =new Person();
person.receive(new Email());
person.receive(new WeiXin());
}
}
interface IReceive{
public String getInfo();
}
class Email implements IReceive{
public String getInfo() {
return "hello";
}
}
class WeiXin implements IReceive{
@Override
public String getInfo() {
return "weixin ok";
}
}
//方式一:简单,但是如果对象增加,相应的方法也要增加。
// 解决:所以要引入接口,对接口产生依赖
//class Person{
// public void receive(Email email) {
// System.out.println(email.getInfo());
// }
//}
//方法二
class Person{
public void receive(IReceive iReceive) {
System.out.println(iReceive.getInfo());
}
}
依赖倒转原则的注意事项和细节:
- 低层模块尽量都要有抽象类和接口
- 变量的声明类型尽量是抽象类或接口
- 继承时遵循里氏替换原则
(4)里氏替换原则
介绍:
- 我们引用基类的地方必须能透明的使用其子类的对象
- 在使用继承时,在子类中尽量不要重写父类的方法
- 继承让两个类的耦合性增强了,在适当的情况下可以使用聚合,组合,依赖
实例:
package com.kun.principle.liskov;
public class Liskov {
public static void main(String[] args) {
A a =new A();
System.out.println("11-3="+a.fun1(11, 3));
System.out.println("1-3="+a.fun1(1, 3));
B b=new B();
System.out.println("11+3="+b.fun1(11, 3));
System.out.println("1+3="+b.fun1(1, 3));
System.out.println("11+3+9="+b.fun2(11, 3));
System.out.println("11-3="+b.fun3(11, 3));
}
}
//解决方法
class Base{
}
class A extends Base{
public int fun1(int num1,int num2) {
return num1-num2;
}
}
class B extends Base{
private A a=new A();
public int fun1(int a, int b) {
return a+b;
}
public int fun2(int a,int b) {
return fun1(a, b)+9;
}
public int fun3(int a,int b) {
return this.a.fun1(a, b);
}
}
//之前代码,违背里氏替换原则
//class A{
// public int fun1(int num1,int num2) {
// return num1-num2;
// }
//}
//class B extends A{
// public int fun1(int a, int b) {
// return a+b;
// }
// public int fun2(int a,int b) {
// return fun1(a, b)+9;
// }
//}
(5)开闭原则
介绍:
- 对一个软件实体,模块和函数应该扩展开放,对修改关闭。
- 用抽象构建框架,用实现扩展细节
- 通过扩展软件实体的行为来变化,而不是修改
- 编程中遵循各个原则,各个原则都遵循开闭原则。
实例:改进前
//缺点:增加一个其他图形类,要创建一个类,然后在GraphicEditor添加判断,添加方法,修改代码太多
public class Ocp {
public static void main(String[] args) {
GraphicEditor graphicEditor=new GraphicEditor();
graphicEditor.drawShape(new Rectangle());
graphicEditor.drawShape(new Circle());
}
}
class GraphicEditor{
public void drawShape(Shape s) {
if (s.m_type==1) {
drawRectangle(s);
}else if (s.m_type==2) {
drawClircle(s);
}
}
public void drawRectangle(Shape r) {
System.out.println("ju xing");
}
public void drawClircle(Shape r) {
System.out.println("yuan");
}
}
class Shape{
int m_type;
}
class Rectangle extends Shape{
Rectangle(){
super.m_type=1;
}
}
class Circle extends Shape{
Circle(){
super.m_type=2;
}
}
改进后的代码:
package com.kun.principle.ocp;
public class Ocp {
public static void main(String[] args) {
GraphicEditor graphicEditor=new GraphicEditor();
graphicEditor.drawShape(new Rectangle());
graphicEditor.drawShape(new Circle());
}
}
class GraphicEditor{
public void drawShape(Shape s) {
s.draw();
}
}
abstract class Shape{
public abstract void draw();
}
class Rectangle extends Shape{
@Override
public void draw() {
System.out.println("ju xing");
}
}
class Circle extends Shape{
@Override
public void draw() {
System.out.println("yuan");
}
}
(6)迪米特法则
介绍:
- 一个对象应该对其他对象保持最少的了解
- 类和类关系越密切。耦合度越大。
- 迪米特法则又叫最少知道法则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类尽量把自己封装起来,只提供public方法。
- 迪米特定义:只和直接朋友通信
实例:
创建一个对象
遍历输出对象
分析:
SchoolManager的直接朋友类Employee
class SchoolManager
//返回学枚总部的员工
public List<Employee>getAllEmployee(){
List<Employee>list new ArrayList<Employee>();
for(inti=0;i<5;i++){//这里我们增加了5个员工到1ist
Employee emp new Employee();
emp.setId("学校总部员工id="+i);
list.add(emp);
}
return list;
}
注意细节
- 迪米特法则的核心是降低类之间的耦合
- 但是注意:由于每个类都减少了不必要的依赖,因此迪米特法则只是要求降低耦合
(7)合成复用原则
介绍:
- 尽量使用合成和聚合的方式,而不是使用继承。