这是我参与更文挑战的第15天,活动详情查看: 更文挑战
设计模式
在前两篇设计模式一、设计模式二我们已经讲了四种原则,接下来讲解的是开闭原则和迪米特法则。
开闭原则
最重要最基础的原则,对扩展开放,对修改关闭。通过使用接口和抽象类来实现在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。
比如我们绘制图形,起初我们只绘制矩形和圆形,代码是这样写的
package com.wangscaler.openclose;
/**
* @author wangscaler
* @date 2021.06.17 11:14
*/
public class OpenClosePrinciple {
public static void main(String[] args) {
Graphic graphic = new Graphic();
graphic.drawRectangle(new Rectangle());
graphic.drawCircular(new Circular());
}
static class Graphic {
public void drawShape(Shape shape) {
if (shape.type == 1) {
drawCircular(shape);
} else if (shape.type == 2) {
drawRectangle(shape);
}
}
public void drawRectangle(Shape shape) {
System.out.println("绘制矩形...");
}
public void drawCircular(Shape shape) {
System.out.println("绘制圆形...");
}
}
static class Shape {
int type;
}
static class Circular extends Shape {
Circular() {
super.type = 1;
}
}
static class Rectangle extends Shape {
Rectangle() {
super.type = 2;
}
}
}
当我们添加新的图形梯形的时候,按照这种方式的话代码就得这样改
错误方式
package com.wangscaler.openclose;
/**
* @author wangscaler
* @date 2021.06.17 11:14
*/
public class OpenClosePrinciple1 {
public static void main(String[] args) {
Graphic graphic = new Graphic();
graphic.drawRectangle(new Rectangle());
graphic.drawCircular(new Circular());
graphic.drawTrapezoid(new Trapezoid());
}
static class Graphic {
public void drawShape(Shape shape) {
if (shape.type == 1) {
drawCircular(shape);
} else if (shape.type == 2) {
drawRectangle(shape);
}
else if(shape.type == 3){
drawTrapezoid(shape);
}
}
public void drawRectangle(Shape shape) {
System.out.println("绘制矩形...");
}
public void drawCircular(Shape shape) {
System.out.println("绘制圆形...");
}
public void drawTrapezoid(Shape shape) {
System.out.println("绘制梯形...");
}
}
static class Shape {
int type;
}
static class Circular extends Shape {
Circular() {
super.type = 1;
}
}
static class Rectangle extends Shape {
Rectangle() {
super.type = 2;
}
}
static class Trapezoid extends Shape {
Trapezoid() {
super.type = 3;
}
}
}
这样虽然可以拿到正确结果,但是改的代码较多,并不能实现热拔插效果,我们不仅修改了提供方的代码(增加了Trapezoid),还修改了使用方的代码(Graphic)。我们应该将Shape变成抽象类,有新的图形时,只需要增加新的图形类去继承这个抽象类就可以了
正确的方式
package com.wangscaler.openclose;
/**
* @author wangscaler
* @date 2021.06.17 11:14
*/
public class OpenClosePrinciple2 {
public static void main(String[] args) {
Graphic graphic = new Graphic();
graphic.drawShape(new Rectangle());
graphic.drawShape(new Circular());
}
static class Graphic {
public void drawShape(Shape shape) {
shape.draw();
}
}
static abstract class Shape {
public abstract void draw();
}
static class Circular extends Shape {
@Override
public void draw() {
System.out.println("绘制圆形...");
}
}
static class Rectangle extends Shape {
@Override
public void draw() {
System.out.println("绘制矩形...");
}
}
}
这时候我们增加新的图形矩形,只需要修改成
package com.wangscaler.openclose;
/**
* @author wangscaler
* @date 2021.06.17 11:14
*/
public class OpenClosePrinciple3 {
public static void main(String[] args) {
Graphic graphic = new Graphic();
graphic.drawShape(new Rectangle());
graphic.drawShape(new Circular());
graphic.drawShape(new Trapezoid());
}
static class Graphic {
public void drawShape(Shape shape) {
shape.draw();
}
}
static abstract class Shape {
public abstract void draw();
}
static class Circular extends Shape {
@Override
public void draw() {
System.out.println("绘制圆形...");
}
}
static class Rectangle extends Shape {
@Override
public void draw() {
System.out.println("绘制矩形...");
}
}
static class Trapezoid extends Shape {
@Override
public void draw() {
System.out.println("绘制梯形...");
}
}
}
总结: 开闭原则对扩展开放,对修改关闭。我们新增梯形,只需要新增加梯形这个类,让我们的梯形去继承shape抽象类并实现抽象类的方法,此时我们不需要修改原有的代码,就实现了我们想要的结果。
迪米特法则
一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。即只和直接的朋友(方法参数、成员变量、方法返回值)通信。
比如 学校校长想查某个班的人数,所以
package com.wangscaler.leastknowledgeprinciple;
import java.util.ArrayList;
import java.util.List;
/**
* @author wangscaler
* @date 2021.06.17 14:09
*/
public class LeastKnowledgePrinciple {
public static void main(String[] args) {
Principal principal = new Principal();
principal.commond(new Teacher());
}
static class Principal {
public void commond(Teacher teacher) {
List<Student> students = new ArrayList<Student>();
for (int i = 0; i < 20; i++) {
students.add(new Student());
}
teacher.count(students);
}
}
static class Teacher {
public void count(List<Student> students) {
System.out.println("学生的数量是:" + students.size());
}
}
static class Student {
}
}
在这里,我们在校长的commond的方法里出现了Student,他就不是方法参数、成员变量还不是方法返回值,所以说Student不是Principal的直接朋友,这样就是违反了迪米特法则。那么应该怎么修改呢,因为Student和Teacher是直接的朋友
package com.wangscaler.leastknowledgeprinciple;
import java.util.ArrayList;
import java.util.List;
/**
* @author wangscaler
* @date 2021.06.17 14:09
*/
public class LeastKnowledgePrinciple1 {
public static void main(String[] args) {
List<Student> students = new ArrayList<Student>();
for (int i = 0; i < 20; i++) {
students.add(new Student());
}
Principal principal = new Principal();
principal.commond(new Teacher(students));
}
static class Principal {
public void commond(Teacher teacher) {
teacher.count();
}
}
static class Teacher {
private List<Student> students;
public Teacher(List<Student> students) {
this.students = students;
}
public void count() {
System.out.println("学生的数量是:" + students.size());
}
}
static class Student {
}
}
学生成为老师的成员变量,老师和学生是直接朋友,校长和老师是直接朋友。
总结: 从上述例子可以看出,迪米特法则可以降低耦合。尽量避免不是直接的朋友(局部变量)出现在类中。