当前位置: 首页 > news >正文

一、《重学设计模式》-设计模式简介

1. 设计模式分类

序号模式&描述包括
1创建型模式1.工厂 2.抽象工厂 3.建造者 4.原型 5.单例
2结构型模式1.适配器 2.桥接 3.过滤器 4.组合 5.装饰器 6.外观 7.享元 8.代理
3行为模式1.责任链 2.命令 3.解释器 4.迭代器 5.中介者 6.备忘录 7.观察者 8.状态 9.空对象 10.策略 11.模板 12.访问者

2. 设计模式关系图

在这里插入图片描述

3. 设计模式的七大原则

  • 单一职责( 一个类和方法只做一件事 )
  • 里⽒替换( 多态,子类可扩展父类 )
  • 依赖倒置( 细节依赖抽象,下层依赖上层 )
  • 接口隔离( 建⽴单一接口 )
  • 迪米特原则( 最少知道,降低耦合 )
  • 开闭原则( 抽象架构,扩展实现 )
  • 合成复用原则
1. 单一职责

方案一

public class Demo1 {
    
    public static void main(String[] args) {
        SingleResponsibility singleResponsibility = new SingleResponsibility();

        singleResponsibility.run("小鸡");
        singleResponsibility.run("小鱼");
        singleResponsibility.run("小鸟");
    }

    static class SingleResponsibility {
        public void run(String name) {
            System.out.println(name + " 在跑");
        }
    }
}
=========================
小鸡 在跑
小鱼 在跑
小鸟 在跑

以上代码run方法违反了单一职责原则,解决方案也很简单,将SingleResponsibility 分成三个,陆地、天空、水中

方案二

public class Demo2 {

    public static void main(String[] args) {
        SingleResponsibilityLand singleResponsibility1 = new SingleResponsibilityLand();
        SingleResponsibilitySky singleResponsibility2 = new SingleResponsibilitySky();
        SingleResponsibilityWater singleResponsibility3 = new SingleResponsibilityWater();

        singleResponsibility1.run("小鸡");
        singleResponsibility3.run("小鱼");
        singleResponsibility2.run("小鸟");
    }

    static class SingleResponsibilityLand {
        public void run(String name) {
            System.out.println(name + " 在跑");
        }
    }

    static class SingleResponsibilitySky {
        public void run(String name) {
            System.out.println(name + " 在飞");
        }
    }

    static class SingleResponsibilityWater {
        public void run(String name) {
            System.out.println(name + " 在游");
        }
    }

}
===================
小鸡 在跑
小鱼 在游
小鸟 在飞 

成功解决了方案一的缺陷,遵守了单一职责,但是这样做改动很大,分解了多个类,修改了main方法

方案三

    public static void main(String[] args) {
        SingleResponsibility singleResponsibility = new SingleResponsibility();

        singleResponsibility.runLand("小鸡");
        singleResponsibility.runWater("小鱼");
        singleResponsibility.runSky("小鸟");
    }

    static class SingleResponsibility {
        public void runLand(String name) {
            System.out.println(name + " 在跑");
        }

        public void runWater(String name) {
            System.out.println(name + " 在游");
        }

        public void runSky(String name) {
            System.out.println(name + " 在飞");
        }
    }

这种方法没有对最初的类进行大的修改,只是增加了方法,虽然没有在类级别遵守单一职责,但是在方法上面满足了单一职责

注意事项

  1. 降低类的复杂度,一个类只负责一项职责
  2. 提高类的可读性,可维护性
  3. 降低变更引起的风险
  4. 通常情况下,应当遵守单一职责原则,只有逻辑足够简单,才可以在代码级违反单一职责原则;只有类中方法数量足够少,可以在方法级别保持单一职责原则
2. 接口隔离原则

方案一

public class Demo2_1 {

    public static void main(String[] args) {
        A a = new A();
        a.opration1(new C());
        a.opration2(new C());
        a.opration5(new C());

        B b = new B();
        b.opration1(new D());
        b.opration3(new D());
        b.opration4(new D());
    }
}


interface Interface1{
    void opration1();
    void opration2();
    void opration3();
    void opration4();
    void opration5();
}

class A {
    public void opration1(Interface1 interface1) {
        interface1.opration1();
    }

    public void opration2(Interface1 interface1) {
        interface1.opration2();
    }

    public void opration5(Interface1 interface1) {
        interface1.opration5();
    }
}

class B {
    public void opration1(Interface1 interface1) {
        interface1.opration1();
    }

    public void opration3(Interface1 interface1) {
        interface1.opration3();
    }

    public void opration4(Interface1 interface1) {
        interface1.opration4();
    }
}

class C implements Interface1{
    @Override
    public void opration1() {
        System.out.println("C opration1");
    }

    @Override
    public void opration2() {
        System.out.println("C opration2");
    }

    @Override
    public void opration3() {
        System.out.println("C opration3");
    }

    @Override
    public void opration4() {
        System.out.println("C opration4");
    }

    @Override
    public void opration5() {
        System.out.println("C opration5");
    }
}
class D implements Interface1{
    @Override
    public void opration1() {
        System.out.println("D opration1");
    }

    @Override
    public void opration2() {
        System.out.println("D opration2");
    }

    @Override
    public void opration3() {
        System.out.println("D opration3");
    }

    @Override
    public void opration4() {
        System.out.println("D opration4");
    }

    @Override
    public void opration5() {
        System.out.println("D opration5");
    }
}

类A通过接口 Interface1 依赖类C,类B通过接口 Interface1 依赖类D,如果接口 Interface1对于类C和类D来说不是最小接口,那么类C和类D必须去实现他们不需要的方法, 改进办法,将interface1拆分成三个接口,让他们分别实现不同的接口

方案二

public class Demo2_2 {

    public static void main(String[] args) {
        A1 a = new A1();
        a.opration1(new C1());
        a.opration2(new C1());
        a.opration5(new C1());

        B1 b = new B1();
        b.opration1(new D1());
        b.opration3(new D1());
        b.opration4(new D1());
    }
}


interface Interface21{
    void opration1();
}
interface Interface22{
    void opration2();
    void opration5();
}
interface Interface23{
    void opration3();
    void opration4();

}

class A1 {
    public void opration1(C1 interface1) {
        interface1.opration1();
    }

    public void opration2(C1 interface1) {
        interface1.opration2();
    }

    public void opration5(C1 interface1) {
        interface1.opration5();
    }
}

class B1 {
    public void opration1(D1 interface1) {
        interface1.opration1();
    }

    public void opration3(D1 interface1) {
        interface1.opration3();
    }

    public void opration4(D1 interface1) {
        interface1.opration4();
    }
}

class C1 implements Interface21, Interface22{
    @Override
    public void opration1() {
        System.out.println("C opration1");
    }

    @Override
    public void opration2() {
        System.out.println("C opration2");
    }

    @Override
    public void opration5() {
        System.out.println("C opration5");
    }
}
class D1 implements Interface21, Interface23{
    @Override
    public void opration1() {
        System.out.println("D opration1");
    }

    @Override
    public void opration3() {
        System.out.println("D opration3");
    }

    @Override
    public void opration4() {
        System.out.println("D opration4");
    }
}

方案二将接口全部拆分,依赖类只需要实现自己需要的接口

3. 依赖倒转(接口或抽象类)

方案一

public class Demo3_1 {
    public static void main(String[] args) {
        Somebody somebody = new Somebody();
        somebody.receive(new Email());
    }
}

class Email{
    public void say(){
        System.out.println("邮件");
    }
}

class Somebody{
    // 传参固定,扩展其他内容有困难
    public void receive(Email email){
        email.say();
    }
}

Somebody如果要实现接收微信,短信消息扩展困难

方案二

public class Demo3_2 {
    public static void main(String[] args) {
        XiaoQiang xiaoQiang = new XiaoQiang();
        xiaoQiang.receive(new Wechat());
        xiaoQiang.receive(new SMS());
    }
}

interface Message{
    void say();
}

class Wechat implements Message{
    public void say(){
        System.out.println("微信");
    }
}
class SMS implements Message{
    public void say(){
        System.out.println("短信");
    }
}


class XiaoQiang{
    public void receive(Message message){
        message.say();
    }
}

方案二提供公共接口,参数用接口形式传递,可以接收不同类型的消息,同时好扩展

依赖关系传递

  • 接口传递
  • 构造器传递
  • setter方法传递
4. 里氏替换原则(继承)

子类尽量不要重写父类的方法,继承实际上是让两个类的耦合性增强,适当的使用聚合、组合、依赖来解决问题

方案一

public class Demo4_1 {
    public static void main(String[] args) {
        A4 a = new A4();
        System.out.println("1+1="+a.fun1(1,1));
        System.out.println("1+3="+a.fun1(1,3));

        B4 b = new B4();
        System.out.println("1+1="+b.fun1(1,1));
        System.out.println("1+1+9="+b.fun2(1,1));
    }

}
class A4 {
    public int fun1(int a , int b ){
        return a+b;
    }
}

class B4 extends A4{
    //重写父类方法
    public int fun1(int a , int b ){
        return a-b;
    }

    public int fun2(int a , int b ){
        return fun1(a,b) + 9;
    }
}

方案一存在问题,B继承A 但是修改了A方法的逻辑,导致后面使用相同方法但是意义不一样,和预想结果发生偏差

方案二

public class Demo4_2 {
    public static void main(String[] args) {
        A42 a = new A42();
        System.out.println("1+1=" + a.fun1(1, 1));
        System.out.println("1+3=" + a.fun1(1, 3));

        B42 b = new B42();
        System.out.println("1+1=" + b.fun1(1, 1));
        System.out.println("1+1+9=" + b.fun2(1, 1));
    }

}

class Base4 {

}

class A42 extends Base4 {
    public int fun1(int a, int b) {
        return a + b;
    }
}

class B42 extends Base4 {
    //通过组合方式解决方法名称相同,内容不同
    A42 a42 = new A42();

    //重写父类方法
    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 a42.fun1(a, b);
    }
}

提取公共类,实现各自继承,解决单一继承修改方法导致方法意义变更的问题,如果B想使用A,使用组合方式实现

5. 开闭原则

扩展开放(提供方),修改关闭(使用方),抽象构建框架,实现扩展细节

软件变化尽量通过扩展,而不是通过修改

方案一

public class Demo5_1 {
    public static void main(String[] args) {
        Bank bank = new Bank();
        bank.pay(new JDPay());
        bank.pay(new WechatPay());
        bank.pay(new AliPay());
    }
}

class Bank {
    // 使用方
    public void pay(Pay pay) {
        if (pay.type == 1) {
            System.out.println("京东支付");
        } else if (pay.type == 2) {
            System.out.println("微信支付");
        } else if (pay.type == 3) {
            System.out.println("支付宝支付");
        }
    }

}

class Pay {
    int type;
}

class JDPay extends Pay {
    public JDPay() {
        super.type = 1;
    }
}

class WechatPay extends Pay {
    public WechatPay() {
        super.type = 2;
    }
}

class AliPay extends Pay {
    public AliPay() {
        super.type = 3;
    }
}

方案一,当我们想要使用银联支付的时候,需要添加银联支付的类,需要修改实用类,都要修改,不符合开闭原则

方案二

public class Demo5_2 {
    public static void main(String[] args) {
        Bank bank = new Bank();
        bank.pay(new JDPay());
        bank.pay(new WechatPay());
        bank.pay(new AliPay());
    }
}

class Bank {
    // 使用方
    public void pay(Pay pay) {
        pay.pay();
    }

}

abstract class Pay {
    int type;

    abstract void pay();
}

class JDPay extends Pay {
    public JDPay() {
        super.type = 1;
    }

    @Override
    void pay() {
        System.out.println("京东支付");
    }
}

class WechatPay extends Pay {
    public WechatPay() {
        super.type = 2;
    }
    @Override
    void pay() {
        System.out.println("微信支付");
    }
}

class AliPay extends Pay {
    public AliPay() {
        super.type = 3;
    }
    @Override
    void pay() {
        System.out.println("支付宝支付");
    }
}

使用方法二,使用类,无需改动,以后扩展其他支付,只需要增加对应的支付类

6. 迪米特法则

只与直接朋友通信,

直接朋友的定义,成员变量、方法参数,方法返回值,局部变量不是直接朋友

不是直接朋友的类,是陌生的类

判断思路

在类里面找非直接朋友,如果找到,就将非直接朋友迁移到其他类中

7. 合成复用原则

尽量使用聚合/合成方式,而不是使用集成

简单讲类A 有方法f1,类B想使用f1,简单的办法,B继承A,但是继承就提高了AB之间的耦合,A可以作为参数传递给B使用A方法的方法,A也可以作为B的成员变量通过set方法传递过去,也可以直接在B中通过new来进行组合

8.设计模式的核心思想
  • 把需要变化的独立出来,不要和那些不需要变化的代码混合起来

  • 针对接口编程而不是针对实现编程

  • 为了交互对象之间松耦合设计而努力

相关文章:

  • 3.9 用户反馈智能分析实战:从情感识别到产品优化的闭环设计指南
  • 低代码(Low Code)全解析:从概念到应用,从选择到价值
  • Spring框架-AOP
  • 【C语言】C语言 食堂自动化管理系统(源码+数据文件)【独一无二】
  • 【git】已上传虚拟环境的项目更改成不再上传虚拟环境
  • cmake:定位Qt的ui文件
  • 练习题:41
  • VideoPipe-使用VLC构建RTSP串流显示
  • 核函数简述
  • RagFlow+Ollama 构建RAG私有化知识库
  • python进阶篇-面向对象
  • 梁文锋亲自挂名DeepSeek发布新论文
  • 将jar安装到Maven本地仓库中
  • 用STC-ISP写延时函数
  • vue从入门到精通(十):绑定样式
  • 从零开始构建一个小型字符级语言模型的详细教程(基于Transformer架构)之一数据准备
  • 6.【线性代数】—— 列空间和零空间
  • spring cloud 微服务部署(2025年)第三章:Nacos、LoadBalancer、GateWay、Ribbon集成之网关Gateway部署
  • 【Java】逻辑运算符详解:、|| 与、 | 的区别及应用
  • 解锁D3.js与PlantUML的交互奥秘:探索知识图谱数据可视化新领域
  • 为什么所有动物里,只有人类幼崽发育得这么慢?
  • 金沙记忆|元谋龙街渡:是起点也是终点
  • “五一”假期出入境人数达1089.6万人次,同比增长28.7%
  • 黔西游船倾覆事故84名落水人员已全部找到,10人不幸遇难
  • 100%关税!特朗普要让美国电影100%美国制造
  • 五一假期旅游大市党政领导靠前调度,重视解决游客反映的问题