赛事中心 / 2025-10-10 23:17:38

系列文章

23种设计模式 —— 设计模式目的以及遵循的七大原则 23种设计模式 —— 单例模式【饿汉式、懒汉式、双重检查、静态内部类、枚举】 23种设计模式 —— 工厂模式【简单工厂、工厂方法、抽象工厂】 23种设计模式 —— 原型模式【克隆羊、浅拷贝、深拷贝】

文章目录

系列文章设计模式目的设计模式七大原则1、单一职责原则2、接口隔离原则3、依赖倒转原则4、里氏替换原则5、开闭原则6、迪米特法则7、合成复用原则

设计模式目的

设计模式的目的是为了提高代码重用性、可读性、可扩展性、可靠性,使得程序呈现出高内聚、低耦合的特性。

代码重用性:相同功能的代码无需多次重复编写可读性:编程按照一定规范,便于其他程序员的阅读和理解可扩展性:当我们可以非常方便简单地增加新功能可靠性:我们增加或删除部分功能时,对原有系统其他功能没有影响高内聚、低耦合:

设计模式七大原则

设计模式原则,其实就是程序员编程时应当遵守的原则,也是各种设计模式的基础(即为什么设计模式要这么设计的依据)。

单一职责原则接口隔离原则依赖倒转原则里氏替换原则开闭原则迪米特法则合成复用原则

1、单一职责原则

对于类来说,就是一个类应该只负责一项职责,如果类A负责了职责1和职责2,当职责1的需求发生改变时,可能对职责2的执行造成影响,因此需要将类A分解为类A1和类A2。

例如下面举一个交通工具类的例子,当程序运行时会出现飞机在公路上运行的尴尬,就是因为这一个交通工具类既负责空中的,也负责陆地的,才导致问题。

public class Main1 {

public static void main(String[] args) {

Vehicle vehicle = new Vehicle();

vehicle.run("汽车");

vehicle.run("飞机");

}

}

//交通工具

class Vehicle{

public void run(String vehicle){

System.out.println(vehicle+"在公路上运行");

}

}

将交通工具类分解为陆地交通工具和空中交通工具,使得一个类只负责一件事,如此虽然遵守了单一职责原则,但改动太大,为了一个方法增加两个类,因此我们还能再简化。

public class Main1 {

public static void main(String[] args) {

RoadVehicle vehicle1 = new RoadVehicle();

vehicle1.runRoad("汽车");

AirVehicle vehicle2 = new AirVehicle();

vehicle2.runAir("飞机");

}

}

//交通工具

class RoadVehicle{

public void runRoad(String vehicle){

System.out.println(vehicle+"在陆地上运行");

}

}

class AirVehicle{

public void runAir(String vehicle){

System.out.println(vehicle+"在天空上运行");

}

}

上面是在类级别上遵守单一职责,而下面这种是在方法级别上遵守单一职责。

class Vehicle{

public void runAir(String vehicle){

System.out.println(vehicle+"在天空上运行");

}

public void runRoad(String vehicle){

System.out.println(vehicle+"在陆地上运行");

}

}

单一职责原则小结:

为了降低类的复杂度,做到一个类只负责一项职责;可以提高类的可读性和可维护性,降低变更引起的风险;通常情况下,我们应当逻辑单一职责原则,只有逻辑足够简单才能在代码上违反单一职责原则,只有类中方法数量很少,才可以只在方法级别上遵守单一职责原则。

2、接口隔离原则

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

为什么会有接口隔离?考虑这么一种情况,现有一个接口包含了三个方法,有类A和类B实现了该接口,而类C和类D依赖于该接口。(这里依赖的意思,类C和D中有方法的参数是接口,而我们可以将实现了接口的类A和B作为C和D方法的参数)。

下面用代码实现。

interface Interface1{

void method1();

void method2();

void method3();

}

class A implements Interface1{

@Override

public void method1() {}

@Override

public void method2() {}

@Override

public void method3() {}

}

class B implements Interface1{

@Override

public void method1() {}

@Override

public void method2() {}

@Override

public void method3() {}

}

class C{

public void c_method1(Interface1 interface1){

interface1.method1();

}

public void c_method2(Interface1 interface1){

interface1.method2();

}

}

class D{

public void d_method3(Interface1 interface1){

interface1.method3();

}

}

public class Main2 {

public static void main(String[] args) {

A a = new A();

B b = new B();

C c = new C();

c.c_method1(a);

D d = new D();

d.d_method3(b);

}

}

这样的设计明显是有问题的,因为我们的类C只用到接口的方法一和方法二,而类D只用到了接口的方法三,因此我们采用接口隔离,将接口分开。

把刚刚的接口Interface1拆分为接口Interface1和Interface2,使得类C和类D分别依赖两个不同接口。

interface Interface1{

void method1();

void method2();

}

interface Interface2{

void method3();

}

class A implements Interface1{

@Override

public void method1() {}

@Override

public void method2() {}

}

class B implements Interface2{

@Override

public void method3() {}

}

class C{

public void c_method1(Interface1 interface1){

interface1.method1();

}

public void c_method2(Interface1 interface1){

interface1.method2();

}

}

class D{

public void d_method3(Interface2 interface2){

interface2.method3();

}

}

3、依赖倒转原则

高层模块不应该依赖底层模块,二者都应该依赖于抽象

抽象不应该依赖于细节,细节要依赖于抽象

抽象在Java中就是指接口或抽象类,细节就是具体的实现类

依赖倒转的中心思想就是面向接口编程

使用接口或抽象类的目的是为了制定好规范,而不涉及任何具体的作用,把展现细节的任务交给它们的实现类。

下面三种方式实现依赖传递:

通过接口实现依赖传递

interface OpenInterface{

public void open(TV tv);

}

interface TV{

public void play();

}

class Open implements OpenInterface{

@Override

public void open(TV tv) {

tv.play();

}

}

class ChangHong implements TV{

@Override

public void play() {

System.out.println("长虹电视打开了!");

}

}

public class DependencyInversion {

public static void main(String[] args) {

ChangHong changHong = new ChangHong();

OpenInterface openInterface = new Open();

openInterface.open(changHong);

}

}

通过构造方法实现依赖传递

interface OpenInterface{

public void open();

}

interface TV{

public void play();

}

class Open implements OpenInterface{

public TV tv;

Open(TV tv){

this.tv = tv;

}

@Override

public void open() {

this.tv.play();

}

}

class ChangHong implements TV{

@Override

public void play() {

System.out.println("长虹电视打开了!");

}

}

public class DependencyInversion {

public static void main(String[] args) {

ChangHong changHong = new ChangHong();

OpenInterface openInterface = new Open(changHong);

}

}

通过setter实现依赖传递

interface OpenInterface{

public void open();

public void setTV(TV tv);

}

interface TV{

public void play();

}

class Open implements OpenInterface{

public TV tv;

@Override

public void open() {

this.tv.play();

}

@Override

public void setTV(TV tv) {

this.tv = tv;

}

}

class ChangHong implements TV{

@Override

public void play() {

System.out.println("长虹电视打开了!");

}

}

public class DependencyInversion {

public static void main(String[] args) {

ChangHong changHong = new ChangHong();

OpenInterface openInterface = new Open();

openInterface.setTV(changHong);

openInterface.open();

}

}

依赖倒转小结:

底层模块尽量都要有抽象类或接口,这样程序稳定性更好!变量的声明类型尽量都是抽象类或接口,这样我们的变量引用和实际对象间就有一个缓冲,利于程序扩展和优化。继承时遵循里氏替换。

4、里氏替换原则

所有引用基类的地方,必须能透明的使用其子类。

因此,在继承时,子类尽量不要重写父类的方法。

继承会让两个类的耦合性增强,因此适当情况下,可以通过聚合、组合、依赖来解决问题。(假如A继承于B,我们可以抽取其公共部分为Base类,然后使用组合,在A类中创建B的对象)

5、开闭原则

开闭原则(Open Closed Principle)是编程中最基础、最重要的设计原则一个软件实体,例如类、模块、函数应该对扩展开发(针对开发方),对修改关闭(针对使用方)。用抽象构建框架,用实现扩展细节。当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有代码来实现变化。编程中遵循的其他原则,以及使用设计模式的目的就是遵守开闭原则。

下面举个例子:这种方式就没有遵循开闭原则,无论是扩展还是修改。假如要新增一个绘制三角形,就要改动很多。

public class Ocp {

public static void main(String[] args) {

GraphicEditor graphicEditor = new GraphicEditor();

graphicEditor.drawRectangle(new Rectangle());

graphicEditor.drawCircle(new Circle());

}

}

//这是一个用于绘图的类【使用方】

class GraphicEditor{

//根据不同类型来绘制不同图形

public void drawShape(Shape shape){

if (shape.type == 1)

drawRectangle(shape);

else if(shape.type == 2)

drawCircle(shape);

}

public void drawRectangle(Shape r){

System.out.println("矩形");

}

public void drawCircle(Shape c){

System.out.println("圆形");

}

}

//图形基类

class Shape{

int type;

}

//矩形

class Rectangle extends Shape{

Rectangle(){

super.type = 1;

}

}

//圆形

class Circle extends Shape{

Circle(){

super.type = 2;

}

}

按照开闭原则方式优化:如果要绘制三角形,只需新增三角形类来继承Shape,既满足对扩展开发,也满足对修改关闭!

package design_principle.ocp.improve;

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 shape){

shape.draw();

}

}

//图形基类

abstract class Shape{

int type;

public abstract void draw();

}

//矩形

class Rectangle extends Shape {

Rectangle(){

super.type = 1;

}

@Override

public void draw() {

System.out.println("矩形");

}

}

//圆形

class Circle extends Shape {

Circle(){

super.type = 2;

}

@Override

public void draw() {

System.out.println("圆形");

}

}

6、迪米特法则

一个对象应该对其他对象保持最少的了解类与类关系越密切,耦合度越大迪米特法则也叫最少知道原则,即一个类对自己依赖的类知道的越少越好。对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供public方法外,不要泄露任何信息。迪米特法则还有个更简单的定义:只与直接朋友通信。直接朋友:只要两个对象间有耦合关系,那么它们就是朋友。耦合包括依赖、关联、组合、聚合等等。其中,我们将成员变量、方法参数、方法返回值中的类称为直接朋友,而出现在局部变量中的类(例如class A的一个方法里有class B对象)不是直接朋友。换句话说,陌生的类最好不要以局部变量的形式出现在类的内部。

注意:迪米特法则的核心只要求降低类之间的耦合,并不是完全没有依赖。

7、合成复用原则

尽量使用合成/聚合的方式,而不是使用继承。下面四种方式都可以让B使用A的方法,但继承的方式耦合度太高。

日本乐器:弦弓传统乐器(小提琴、kokyu)、日本民族管乐器等
问道怎么刷道比较快 问道快速刷道方法