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

发布于:2025-02-19 ⋅ 阅读:(26) ⋅ 点赞:(0)

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.设计模式的核心思想
  • 把需要变化的独立出来,不要和那些不需要变化的代码混合起来

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

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


网站公告

今日签到

点亮在社区的每一天
去签到