Java 常用设计原则和设计模式

Java 常用设计原则和设计模式

1.常用的设计原则

1.1 软件开发的流程

需求分析文档、概要设计文档、详细设计文档、编码和测试、安装和调试、维护和升级

1.2 常用的设计原则
  • 开闭原则(Open Close Principle)

    • 对扩展开放对修改关闭,为了使程序的扩展性好,易于维护和升级。
  • 里氏代换原则(Liskov Substitution Principle)

    • 任何基类可以出现的地方,子类一定可以出现,多使用多态的方式。(屏蔽不同子类的差异性,已实现通用的编程方法,带来不同的效果
  • 依赖倒转原则(Dependence Inversion Principle)

    • 尽量多依赖于抽象类或接口而不是具体实现类,对子类具有强制性和规范性
  • 接口隔离原则(Interface Segregation Principle)

    • 尽量多使用小接口而不是大接口,避免接口的污染,降低类之间耦合度。(否则一些不需要接口的抽象方法的实现类也必须重写接口的一些方法,造成了矛盾)
  • 迪米特法则(最少知道原则)(Demeter Principle)

    • 一个实体应当尽量少与其他实体之间发生相互作用,使系统功能模块相对独立。

    • 高内聚,低耦合。
  • 合成复用原则(Composite Reuse Principle)

    • 尽量多使用合成/聚合的方式,而不是继承的方式。
合成复用原则案例:
package com.lagou.task21;

/**
 * @author 云梦归遥
 * @date 2021/11/18 21:37
 * @description
 */
public class B {
    // 合成复用原则
    private A a;

    public B(A a) {
        this.a = a;
    }

    public void test() {
        // 调用 A 类中的 show 方法,请问如何实现
        // 可以遵循合成复用原则
        // 在本类中声明一个所需类类型的引用,然后在本类的构造方法中进行初始化
        a.show();
    }
}

2.常用的设计模式

2.1 基本概念
  • 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

  • 设计模式就是一种用于固定场合的固定套路。
2.2 基本分类
  • 创建型模式 - 单例设计模式、工厂方法模式、抽象工厂模式、…
  • 结构型模式 - 装饰器模式、代理模式、…
  • 行为型模式 - 模板设计模式、…

3.设计模式详解

3.1 单例设计模式
  • 单例设计模式主要分为:饿汉式懒汉式,懒汉式需要对多线程进行同步处理。

    • package com.lagou.task21;
      
      /**
       * @author 云梦归遥
       * @date 2021/11/18 21:48
       * @description
       */
      public class Singleton {
          // 2.声明本类类型的引用指向本类类型的对象,使用 private static 关键字修饰
          private static Singleton sin = null;
      
          // 1.私有化构造方法,使用 private 关键字修饰
          private Singleton() {}
      
          // 3.提供公有的 get 方法负责将上述对象返回回去,使用 public static 关键字修饰
          // 懒汉式实现代码同步
          public static /*synchronized*/ Singleton getInstance(){
              /*synchronized (Singleton.class) {
                  if (null == sin) {
                      sin = new Singleton();
                  }
                  return sin;
              }*/
      
              // 懒汉式的升级版本
              if (null == sin) {
                  synchronized (Singleton.class) {
                      if (null == sin) {
                          sin = new Singleton();
                      }
                  }
              }
              return sin;
          }
      }
      
3.2 普通工厂模式
  • 普通工厂方法模式就是建立一个工厂类,对实现了同一接口的不同实现类进行实例的创建。

  • 类图结构:
    • 三条线:上面是类名或接口名,中间是成员变量,下面是成员方法

    • 在这里插入图片描述

    • 上述类图结构的代码实现:

      Sender.java
      package com.lagou.task21;
      
      /**
       * @author 云梦归遥
       * @date 2021/11/18 22:20
       * @description
       */
      public interface Sender {
          // 自定义抽象方法来描述发送的行为
          void send();
      }
      
      MailSender.java
      package com.lagou.task21;
      
      /**
       * @author 云梦归遥
       * @date 2021/11/18 22:20
       * @description
       */
      public class MailSender implements Sender {
      
          @Override
          public void send() {
              System.out.println("正在发送邮件......");
          }
      }
      
      SmsSender.java
      package com.lagou.task21;
      
      /**
       * @author 云梦归遥
       * @date 2021/11/18 22:21
       * @description
       */
      public class SmsSender implements Sender {
      
          @Override
          public void send() {
              System.out.println("正在发送短信.....");
          }
      }
      
      SendFactory.java
      package com.lagou.task21;
      
      /**
       * @author 云梦归遥
       * @date 2021/11/18 22:22
       * @description
       */
      public class SendFactory {
          // 自定义成员方法实现对象的创建
          public Sender produce(String type) {
              if ("mail".equals(type)) {
                  return new MailSender();
              }
              if ("sms".equals(type)) {
                  return new SmsSender();
              }
              return null;
          }
      }
      
      SendFactoryTest.java
      package com.lagou.task21;
      
      /**
       * @author 云梦归遥
       * @date 2021/11/18 22:25
       * @description
       */
      public class SendFactoryTest {
      
          public static void main(String[] args) {
      
              // 缺点:代码复杂,可读性较差
              // 优点:扩展性和可维护性更强
              // 1.声明 SendFactory 类型的引用 指向 SendFactory 类型的对象
              SendFactory sf = new SendFactory();
              // 2.调用生产方法来实现对象的创建
              Sender sender = sf.produce("mail"); // 实现了返回值对象的多态
              // 3.使用对象调用方法来模拟发送短信
              sender.send(); // 正在发送邮件......
      
              System.out.println("=================================");
              // 优点:代码简单,可读性强,在创建单个对象时有优势
              // 缺点:扩展性和可维护性略差
              Sender sender1  =new MailSender();
              sender.send(); // 正在发送邮件......
          }
      }
      
  • 普通工厂模式的缺点:

    • 在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,并且可能出现空指针异常。
3.3 多个工厂方法模式
  • 将不同的类创建对象在工厂中写成不同的方法,相当于创建了多个工厂
  • 在这里插入图片描述

  • 上述改进代码:

    SendFactory.java
    package com.lagou.task21;
    
    /**
     * @author 云梦归遥
     * @date 2021/11/18 22:22
     * @description
     */
    public class SendFactory {
        // 自定义成员方法实现对象的创建
        public Sender produce(String type) {
            if ("mail".equals(type)) {
                return new MailSender();
            }
            if ("sms".equals(type)) {
                return new SmsSender();
            }
            return null;
        }
    
        // 以下内容是新增加的,可以针对不同的实现类创建不同的对象
        public Sender produceMail() {
            return new MailSender();
        }
    
        public Sender produceSms() {
            return new SmsSender();
        }
    }
    
    SendFactoryTest.java
    System.out.println("=================================");
    // 多个工厂方法模式
    SendFactory sf2 = new SendFactory();
    Sender sender2 = sf2.produceMail();
    sender2.send(); // 正在发送邮件......
    
  • 缺点:
    • 在多个工厂方法模式中,为了能够正确创建对象,先需要创建工厂类的对象才能调用工厂类中的生产方法。
3.4 静态工厂模式
  • 在这里插入图片描述

  • 对于多个工厂的模式,可以对创建对象的方法加上 static 关键字,变成静态方法,就不需要先创建工厂对象,然后在调用方法了,直接通过类名方式调用方法
  • 上述代码的改进:

    SendFactory.java
    package com.lagou.task21;
    
    /**
     * @author 云梦归遥
     * @date 2021/11/18 22:22
     * @description
     */
    public class SendFactory {
        // 自定义成员方法实现对象的创建
        public Sender produce(String type) {
            if ("mail".equals(type)) {
                return new MailSender();
            }
            if ("sms".equals(type)) {
                return new SmsSender();
            }
            return null;
        }
    
        // 以下内容是新增加的,可以针对不同的实现类创建不同的对象
        public static Sender produceMail() {
            return new MailSender();
        }
    
        public static Sender produceSms() {
            return new SmsSender();
        }
    }
    
    SendFactoryTest.java
    System.out.println("=================================");
    // 多个工厂方法模式
    //SendFactory sf2 = new SendFactory();
    // 静态工厂方法模式
    Sender sender2 = SendFactory.produceMail();
    sender2.send(); // 正在发送邮件......
    
  • 缺点:
    • 工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序生产新的产品,就必须对工厂类的代码进行修改,这就违背了开闭原则
3.5 抽象工厂模式
  • 在这里插入图片描述

  • 将原来的工厂类变成了工厂接口,然后对于工厂接口去实现各自的实现类,通过多态,实现了调用方法
  • 代码的实现:

    Provider.java
    package com.lagou.task21;
    
    /**
     * @author 云梦归遥
     * @date 2021/11/18 22:59
     * @description
     */
    public interface Provider {
        // 自定义抽象方法描述产品的生产
        Sender produce();
    }
    
    MailSenderFactory.java
    package com.lagou.task21;
    
    /**
     * @author 云梦归遥
     * @date 2021/11/18 23:00
     * @description
     */
    public class MailSenderFactory implements Provider {
    
        @Override
        public Sender produce() {
            return new MailSender();
        }
    }
    
    SmsSenderFactory.java
    package com.lagou.task21;
    
    /**
     * @author 云梦归遥
     * @date 2021/11/18 23:01
     * @description
     */
    public class SmsSenderFactory implements Provider {
    
        @Override
        public Sender produce() {
            return new SmsSender();
        }
    }
    
    SendFactoryTest.java
    System.out.println("=================================");
    Provider provider  = new MailSenderFactory();
    Sender sender3 = provider.produce();
    sender3.send(); // 正在发送邮件......
    
3.6.装饰器
  • 装饰器模式就是给一个对象动态的增加一些新功能,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。
  • 类图结构:

    • 在这里插入图片描述
  • 实际意义:
    • 可以实现一个类功能的扩展。
    • 可以动态的增加功能,而且还能动态撤销(继承不行)。
    • 缺点:产生过多相似的对象,不易排错。
装饰器图示代码实现:
Sourceable.java
package com.lagou.task21;

/**
 * @author 云梦归遥
 * @date 2021/11/19 8:59
 * @description
 */
public interface Sourceable {
    // 定义抽象方法
    void method();
}
Source.java
package com.lagou.task21;

/**
 * @author 云梦归遥
 * @date 2021/11/19 8:59
 * @description
 */
public class Source implements Sourceable {

    @Override
    public void method() {
        System.out.println("素颜可以如此之美");
    }
}
Decorator.java
package com.lagou.task21;

import javax.sql.DataSource;

/**
 * @author 云梦归遥
 * @date 2021/11/19 9:03
 * @description
 */
public class Decorator implements Sourceable {
    private Sourceable source;

    // 合成复用原则
    public Decorator(Sourceable source) {
        this.source  = source;
    }

    @Override
    public void method() {
        source.method(); // 保证原有功能不变
        System.out.println("化妆后你会更美");
    }
}
SourceableTest.java
package com.lagou.task21;

/**
 * @author 云梦归遥
 * @date 2021/11/19 9:00
 * @description
 */
public class SourceableTest {

    public static void main(String[] args) {

        Sourceable sourceable = new Source();
        sourceable.method();

        System.out.println("====================================");
        // 接下来使用装饰类实现
        Sourceable sourceable1  =new Decorator(sourceable);
        sourceable1.method();
    }
}
3.7 代理模式
  • 代理模式就是找一个代理类替原对象进行一些操作。
    在这里插入图片描述

  • 意义:
    • 如果在使用的时候需要对原有的方法进行改进,可以采用一个代理类调用原有方法,并且对产生的结果进行控制,这种方式就是代理模式。
    • 使用代理模式,可以将功能划分的更加清晰,有助于后期维护。
  • 代理模式和装饰器模式的比较:
    • 装饰器模式通常的做法是将原始对象作为一个参数传给装饰者的构造器,而代理模式通常在一个代理类中创建一个被代理类的对象。
    • 装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。
Proxy.java
package com.lagou.task21;

/**
 * @author 云梦归遥
 * @date 2021/11/19 9:19
 * @description
 */
public class Proxy implements Sourceable {
    private Source source;

    public Proxy() {
        source = new Source();
    }

    @Override
    public void method() {
        source.method();
        System.out.println("我和装饰器模式是不一样的");
    }
}
SourceableTest.java
package com.lagou.task21;

/**
 * @author 云梦归遥
 * @date 2021/11/19 9:00
 * @description
 */
public class SourceableTest {

    public static void main(String[] args) {

        Sourceable sourceable = new Source();
        sourceable.method(); // 素颜可以如此之美

        System.out.println("====================================");
        // 接下来使用装饰类实现
        Sourceable sourceable1  =new Decorator(sourceable);
        sourceable1.method(); // 素颜可以如此之美 化妆后你会更美

        System.out.println("====================================");
        Sourceable sourceable2 = new Proxy();
        sourceable2.method(); // 素颜可以如此之美 我和装饰器模式是不一样的
    }
}
3.8 模板方法模式
  • 模板方法模式主要指一个抽象类中封装了一个固定流程,流程中的具体步骤可以由不同子类进行不同的实现,通过抽象类让固定的流程产生不同的结果。

  • 类图:

在这里插入图片描述

  • 实际意义:
    • 将多个子类共有且逻辑基本相同的内容提取出来实现代码复用。
    • 不同的子类实现不同的效果形成多态,有助于后期维护。
AbstractCalculator.java
package com.lagou.task21;

/**
 * @author 云梦归遥
 * @date 2021/11/19 9:31
 * @description
 */
public abstract class AbstractCalculator {

    // 自定义构造方法将参数指定的表达式按照参数指定的规则进行切割并返回计算结果
    public int splitExpression(String exp, String op) {
        String[] sArr = exp.split(op);
        return calculate(Integer.parseInt(sArr[0]), Integer.parseInt(sArr[1]));
    }
    // 自定义抽象方法实现计算
    public abstract int calculate(int a, int b);
}
Plus.java
package com.lagou.task21;

/**
 * @author 云梦归遥
 * @date 2021/11/19 9:38
 * @description
 */
public class Plus extends AbstractCalculator {

    @Override
    public int calculate(int a, int b) {
        return a + b;
    }
}
Minus.java
package com.lagou.task21;

/**
 * @author 云梦归遥
 * @date 2021/11/19 9:40
 * @description
 */
public class Minus extends AbstractCalculator {

    @Override
    public int calculate(int a, int b) {
        return a - b;
    }
}
AbstractCalculatorTest.java
package com.lagou.task21;

/**
 * @author 云梦归遥
 * @date 2021/11/19 9:42
 * @description
 */
public class AbstractCalculatorTest {

    public static void main(String[] args) {

        AbstractCalculator abstractCalculator = new Plus();
        int res = abstractCalculator.splitExpression("1+2", "\\+"); // 需要转义,因为在正则表达式中 + 有特殊含义
        System.out.println("运算的结果是:" + res); // 运算的结果是:3
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值