Java设计模式速成

UML类图

UML:统一建模语言
在这里插入图片描述
第一层:类名
第二层:属性
第三层:方法名
属性的完整表示方式:可见性 名称 : 类型[=默认值]
方法的完整表示方式:可见性 名称(参数列表) [:返回类型]
权限修饰符(可见性):public(+),private(-),default,protected(#)
图片对应的代码:

public class Employee {
    private String name;
    private int age;
    private String sex;

    public void walk() {
        System.out.println("walk");
    }
    public void eat(String food){
        System.out.println("eat " + food);
    }
}

类与类之间关系的表示方式

关联关系

对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系
两个类比较”平等“:意思是不存在包含之类的关系

单向关联

在这里插入图片描述
单向关联:用一个单箭头的实现表示,上图表示每一个乘车人都有一个车票
一个类持有另一个类的对象引用(属性),且反过来没有。

双向关联

在这里插入图片描述
双向关联:要用一个不带箭头的实线表示,上图表示在Customer类中维护一个List类型的成员变量,表示一个顾客可以买多个产品,在Product类中维护一个Customer类型的成员变量,表示产品被顾客买走
双方各自持有对方类型的成员变量

自关联

在这里插入图片描述
自关联:用一个带有箭头且自己指向自己的实线表示,上图表示Point类包含类型为Point的成员变量
本类引用本类类型的成员变量

聚合关系

两个类不”平等“,存在包含与被包含的关系
聚合是整体和部分之间的关系,例如一个部门由多个员工组成
在这里插入图片描述
聚合:用一个实线加一个菱形空心箭头表示,箭头指向整体
部分指向整体
区分组合与聚合:组合:整体没了部分也没了
聚合:整体没了部分还在

组合关系

两个类不”平等“,存在包含与被包含的关系
组合是更强烈的整体和部分之间的关系,例如公司不存在后部门也不存在了
在这里插入图片描述
组合:实心菱形箭头实现
部分指向整体

依赖关系

对象之间耦合度最弱的一种关联方式,是临时性的关联,某个类的方法通过局部变量、方法的参数或者对静态方法的调用来访问被依赖类中的某些方法来完成一些职责
在这里插入图片描述
依赖:虚线箭头
一个类作为另一个类的方法的参数或是局部变量

继承关系

对象之间耦合度最大的一种关系,表示一般与特殊的关系,是父类与子类之间的继承关系
在这里插入图片描述
继承:空心三角箭头的实线
大概代码:

class Person {
    private String name;
    private int age;
    private String address;
    public void eat(){
        System.out.println("eat方法被调用");
    }
}

class Student extends Person {
    private String no;
    public void study(){
        System.out.println("study方法被调用");
    }
}
实现关系

类实现接口中所有的抽象操作
在这里插入图片描述
实现:空心三角箭头的虚线
实现类指向接口
大概代码:

interface Car{
    void move();
}

class BMW implements Car{
    private String brandName;
    @Override
    public void move() {
        System.out.println("BMW move");
    }
}

软件设计原则(7种)

开闭原则

对扩展开放,对修改关闭
代码要具有很好的可扩展性,在不修改原有代码的情况下来进行扩展

单一职责原则

指导我们在开发过程中,一个类最好只干一方面的事情

接口隔离原则

跟单一职责原则有点像:接口定义的功能尽量的少,不要一个接口包括太多的能力

里氏替换原则

继承关系的代码开发中,如果需要进行功能的扩展,不要在子类中改变父类已经实现的方法,而是通过新增的方法来扩展父类的功能

依赖倒置原则

在定义类的成员变量、参数类型、返回值类型的时候,不要写某个具体的实现类,而尽量采用接口或者抽象类,这样后续如果要改,只需要增加实现类就好了
定义的时候不要进行实例化

合成复用原则

在编写代码时如果要使用其他类,那么两个类之间尽量使用合成/聚合的方式,而不是使用继承
在这里插入图片描述

用继承关系会产生很多子类,而且新增新的颜色之类的都要修改源代码,违背了开闭原则,使用聚合/组合就能很好的解决
在这里插入图片描述

迪米特原则

如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用,如果其中的一个类需要调用另一个类的某一种方法的话,可以通过第三者转发这个调用

.

设计模式

创建型模式

对象实例化的模式,创建型模式用于解耦对象的实例化过程
创建型模式主要解决:对象创建过程复杂、对象创建逻辑和业务代码耦合太强、需要灵活切换具体实现类 等问题。

模式 核心思想 适合场景
单例模式 Singleton 一个类只有一个实例 配置类、连接池、日志对象
工厂方法 Factory Method 让子类决定创建哪个对象 创建对象逻辑会变化
抽象工厂 Abstract Factory 创建一组相关对象 产品族,比如 Windows UI / Mac UI
建造者 Builder 分步骤创建复杂对象 参数很多、构建过程复杂
原型 Prototype 复制已有对象 创建成本高、需要克隆对象
单例模式 Singleton

这个类提供了一种唯一访问对象的方式,可以直接访问,不需要实例化该类的对象

适合场景
  • 系统配置类
  • 日志工具类
  • 数据库连接池
  • 缓存管理器
分类:
  • 饿汉式
  • 懒汉式
/**
 * 单例模式:饿汉式:太饿了,直接实例化instance
 */
public class singleton {

    private static singleton instance = new singleton();

    //私有化构造方法
    private singleton(){

    }
    public static singleton getInstance(){
        return instance;
    }
}

class Instance{
    //懒汉式 在声明的时候不赋值 比较懒
    private volatile static Instance instance;
    private Instance(){

    }
    public static Instance getInstance(){
        //单线程没问题,多线程就有问题了,可能会创建多个不同实例  使用双重检查锁
        if(instance == null){
            synchronized (Instance.class){
                if(instance == null){
                    instance = new Instance();
                }
            }
        }
        return instance;
    }

}
//测试
class Test{
    //懒汉式
    public static void main(String[] args) {
        singleton s1 = singleton.getInstance();
        singleton s2 = singleton.getInstance();
        System.out.println(s1 == s2);

        System.out.println("-----------");
        //饿汉式
        Instance instance1 = Instance.getInstance();
        Instance instance2 = Instance.getInstance();
        System.out.println(instance1 == instance2);
    }
}

懒汉式:注意线程安全的问题
volatile:解决指令重排序的问题

线程安全懒汉式
优点

  • 节省内存
  • 避免重复创建对象
  • 全局唯一,方便管理共享资源
    缺点
  • 可能破坏单一职责原则
  • 多线程下写不好容易出问题
  • 测试时不太方便替换实例
记忆口诀

单例模式:全局唯一,只创建一次。

.

工厂模式 Factory Method

在这里插入图片描述
定义一个创建对象的接口,客户自己想要哪一个形状(不用关心形状怎么实现的细节),而是通过工厂生产具体形状

核心思想:

不要在业务代码里直接 new 具体类,而是把创建对象的过程交给工厂。

// 接口
interface Shape {
    void draw();
}
// 具体形状
class Rectangle implements Shape{
    @Override
    public void draw() {
        System.out.println("draw Rectangle");
    }
}
class Circle implements Shape{

    @Override
    public void draw() {
        System.out.println("draw Circle");
    }
}
class Square implements Shape{

    @Override
    public void draw() {
        System.out.println("draw Square");
    }
}
// 工厂
class ShapeFactory {
    public static Shape getShape(String type){
        if(type.equals("矩形")){
            return new Rectangle();
        }else if(type.equals("圆形")){
            return new Circle();
        }else if(type.equals("方形")){
            return new Square();
        }else{
            return null;
        }
    }
}
// 客户端
class Demo{
    public static void main(String[] args) {
        Shape shape = ShapeFactory.getShape("矩形");
        shape.draw();
    }
}
优缺点

优点

  • 符合开闭原则
  • 创建对象逻辑和业务代码解耦
  • 新增产品时,不需要修改原来的业务类

缺点

  • 类数量会增加
  • 每新增一个产品,通常要新增一个工厂类
记忆口诀

工厂方法:一个工厂生产一种产品。

.

抽象工厂模式 Abstract Factory
核心思想

工厂方法是创建一个产品,抽象工厂是创建一组相关产品

例如:

Windows 按钮 + Windows 输入框
Mac 按钮 + Mac 输入框

它解决的是 产品族 的创建问题。

interface Button {
    void click();
}

interface TextField {
    void input();
}

class WindowsButton implements Button {
    public void click() {
        System.out.println("点击 Windows 按钮");
    }
}

class WindowsTextField implements TextField {
    public void input() {
        System.out.println("Windows 输入框输入");
    }
}

class MacButton implements Button {
    public void click() {
        System.out.println("点击 Mac 按钮");
    }
}

class MacTextField implements TextField {
    public void input() {
        System.out.println("Mac 输入框输入");
    }
}

interface GUIFactory {
    Button createButton();
    TextField createTextField();
}

class WindowsFactory implements GUIFactory {
    public Button createButton() {
        return new WindowsButton();
    }

    public TextField createTextField() {
        return new WindowsTextField();
    }
}

class MacFactory implements GUIFactory {
    public Button createButton() {
        return new MacButton();
    }

    public TextField createTextField() {
        return new MacTextField();
    }
}

public class Main {
    public static void main(String[] args) {
        GUIFactory factory = new WindowsFactory();

        Button button = factory.createButton();
        TextField textField = factory.createTextField();

        button.click();
        textField.input();
    }
}
优缺点

优点

  • 保证同一产品族对象一起使用
  • 更换产品族很方便,比如从 WindowsFactory 换成 MacFactory
  • 客户端不依赖具体类

缺点

  • 新增产品族方便
  • 新增产品等级麻烦,比如再加一个 Checkbox,所有工厂都要改
记忆口诀

抽象工厂:一个工厂生产一整套产品。

.

建造者模式 Builder
核心思想

当一个对象参数很多、构建过程复杂时,不要写一堆构造方法,而是用 Builder 一步一步构建对象。

if 不使用 Builder 的问题

new Computer("Intel i7", "32G", "1TB", "RTX4060", true, true);

参数太多,可读性差,还容易传错。
so:

class Computer {
    private String cpu;
    private String memory;
    private String disk;
    private String gpu;

    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.memory = builder.memory;
        this.disk = builder.disk;
        this.gpu = builder.gpu;
    }

    public static class Builder {
        private String cpu;
        private String memory;
        private String disk;
        private String gpu;

        public Builder cpu(String cpu) {
            this.cpu = cpu;
            return this;
        }

        public Builder memory(String memory) {
            this.memory = memory;
            return this;
        }

        public Builder disk(String disk) {
            this.disk = disk;
            return this;
        }

        public Builder gpu(String gpu) {
            this.gpu = gpu;
            return this;
        }

        public Computer build() {
            return new Computer(this);
        }
    }

    public void show() {
        System.out.println(cpu + ", " + memory + ", " + disk + ", " + gpu);
    }
}

public class Main {
    public static void main(String[] args) {
        Computer computer = new Computer.Builder()
                .cpu("Intel i7")
                .memory("32GB")
                .disk("1TB SSD")
                .gpu("RTX 4060")
                .build();

        computer.show();
    }
}
优缺点

优点

  • 参数多时更清晰
  • 链式调用,可读性强
  • 可以控制对象构建过程

缺点

  • 类会变多
  • 简单对象没必要使用 Builder
记忆口诀

建造者模式:复杂对象,一步一步造。

.

原型模式 Prototype
核心思想

通过复制已有对象来创建新对象,而不是重新 new

适用场景

适合对象创建成本比较高的情况,比如:

  • 对象初始化很复杂
  • 需要复制大量相似对象
  • 游戏角色复制
  • 表单模板复制
class Student implements Cloneable {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Student clone() {
        try {
            return (Student) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

    public void show() {
        System.out.println(name + "," + age);
    }
}

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("张三", 20);
        Student s2 = s1.clone();

        System.out.println(s1 == s2); // false
        s2.show();
    }
}

注意:浅拷贝和深拷贝
如果对象里有引用类型字段,例如:

private Address address;

普通 clone() 只是浅拷贝,两个对象可能共享同一个 Address。

深拷贝和浅拷贝区别
  • 浅拷贝(Shallow Copy):只拷贝第一层,里面的嵌套对象共用,改一个另一个也变。
  • 深拷贝(Deep Copy):完全复制所有层级,新旧对象完全独立,互不影响。
优缺点

优点

  • 创建对象效率高
  • 可以快速复制已有对象
  • 避免复杂初始化过程

缺点

  • 深拷贝处理麻烦
  • 对象结构复杂时,clone 容易出错
记忆口诀

原型模式:复制一个已有对象。

创建型模式就先到这里了,后续会更结构型模式,有需要的可以关注一波,谢谢啦

更多推荐