31--设计模式、面向对象设计原则

1、设计模式

1.1 设计模式概述

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

设计模式不是一种方法和技术,而是一种思想。

设计模式和具体的语言无关,学习设计模式就是要建立面向对象的思想,尽可能的面向接口编程,低耦合,高内聚,使设计的程序可复用。

学习设计模式能够促进对面向对象思想的理解,反之亦然。它们相辅相成

简单一句话:设计模式就是经验的总结

设计模式的几个要素

  • 名字:必须有一个简单,有意义的名字
  • 问题描述:在何时使用模式
  • 解决方案:描述设计的组成部分以及如何解决问题
  • 效果:描述模式的效果以及优缺点设计模式的分类

设计模式的分类

  • 创建型模式:对象的创建
  • 结构型模式:对象的组成(结构)
  • 行为型模式:对象的行为

创建型模式:简单工厂模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式,单例模式。(6个)

结构型模式:外观模式、适配器模式、代理模式、装饰模式、桥接模式、组合模式、享元模式。(7个)

行为型模式:模版方法模式、观察者模式、状态模式、职责链模式、命令模式、访问者模式、策略模式、备忘录模式、迭代器模式、解释器模式。(10个)

1.2 单例模式详解

1.2.1 什么是单例设计模式

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

1.2.2 单例模式特点

1、单例类只能有一个实例。也就是只有一个对象

2、单例类必须自己创建自己的唯一实例。 写单例构造方法是要私有的

3、单例类必须给所有其他对象提供这一实例。 在该方法中,提供一个方法,用于获取该对象

1.2.3 单例设计模式实现前提条件

私有构造方法

在本类的成员位置,创建出自己类对象

提供公共方法,返回创建的对象 ,该方法必须是静态的

1.2.4 单例模式饿汉式

java 复制代码
package com.suyv.singleton;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 10:46
 * @Description: 饿汉式单例模式
 */
public class A {

    // 2.定义变量接收类的对象
    private static A a = new A();

    // 1.私有化构造器
    private A(){
    }

    // 3.定义静态方法返回类的对象
    public static A getInstance(){
        return a;
    }

}

测试

java 复制代码
package com.suyv.singleton;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 10:49
 * @Description: 饿汉式单例模式测试
 */
public class ADemo01 {

    public static void main(String[] args) {
        A a1 = A.getInstance();
        A a2 = A.getInstance();

        System.out.println(a1);     // com.suyv.singleton.A@677327b6
        System.out.println(a2);     // com.suyv.singleton.A@677327b6

        System.out.println(a1 == a2);       // true
    }
}

1.2.5 单例模式懒汉式

java 复制代码
package com.suyv.singleton;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 10:52
 * @Description: 懒汉式单例模式
 */
public class B {
    // 2.定义静态变量接收创建的对象
    private static B b;

    // 1.私有化构造器
    private B(){

    }

    // 3.定义一个静态方法,第一次创建时才创建对象,后面调用都会返回这一个对象
    public static B getInstance(){
        if (b == null){
            b = new B();
        }
        return b;
    }
}

测试

java 复制代码
package com.suyv.singleton;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 10:56
 * @Description: 懒汉式单例模式测试
 */
public class BDemo01 {

    public static void main(String[] args) {

        B b1 = B.getInstance();
        B b2 = B.getInstance();

        System.out.println(b1);     // com.suyv.singleton.B@677327b6
        System.out.println(b2);     // com.suyv.singleton.B@677327b6

        System.out.println(b1 == b2);       // true

    }
}

1.2.6 单例设计模式的线程安全问题

1.2.6.1 饿汉式没有线程安全问题

饿汉式:在类初始化时就直接创建单例对象,而类初始化过程是没有线程安全问题的

1.2.6.2 懒汉式线程安全问题

问题出现:

java 复制代码
package com.suyv.singleton;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 10:52
 * @Description: 懒汉式单例模式
 */
public class B{
    // 2.定义静态变量接收创建的对象
    private static volatile B b;

    // 1.私有化构造器
    private B(){

    }

    // 3.定义一个静态方法,第一次创建时才创建对象,后面调用都会返回这一个对象
    public static B getInstance(){

        if (b == null){

            try {
                // 让问题暴露更加明显
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            b = new B();
        }
        return b;
    }
}
java 复制代码
package com.suyv.singleton;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 10:56
 * @Description: 懒汉式单例模式线程安全测试
 */
public class BDemo02 {
    static B b1 = null;
    static B b2 = null;

    public static void main(String[] args) {

        Thread t1 = new Thread(){
            @Override
            public void run() {
                b1 = B.getInstance();
            }
        };

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                b2 = B.getInstance();
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        System.out.println(b1);     // com.suyv.singleton.B@677327b6
        System.out.println(b2);     // com.suyv.singleton.B@14ae5a5

        System.out.println(b1 == b2);       // false

    }
}

解决方案:

java 复制代码
package com.suyv.singleton;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 10:52
 * @Description: 懒汉式单例模式
 */
public class B{
    // 2.定义静态变量接收创建的对象
    private static volatile B b;

    // 1.私有化构造器
    private B(){

    }

    // 3.定义一个静态方法,第一次创建时才创建对象,后面调用都会返回这一个对象
    /*public static B getInstance(){

        if (b == null){

            try {
                // 让问题暴露更加明显
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            b = new B();
        }
        return b;
    }*/

    // 使用双重判断,效率更高
    public static B getInstance(){
        if (b == null){
            synchronized (B.class){
                if (b == null){
                    b = new B();
                }
            }
        }
        return b;
    }
}
java 复制代码
package com.suyv.singleton;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 10:56
 * @Description: 懒汉式单例模式线程安全测试
 */
public class BDemo03 {
    static B b1 = null;
    static B b2 = null;

    public static void main(String[] args) {

        Thread t1 = new Thread(){
            @Override
            public void run() {
                b1 = B.getInstance();
            }
        };

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                b2 = B.getInstance();
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        System.out.println(b1);     // com.suyv.singleton.B@677327b6
        System.out.println(b2);     // com.suyv.singleton.B@677327b6

        System.out.println(b1 == b2);       // true

    }
}

解决程线安全问题

双层if判断的原因

  • 方法中加入同步锁,保证线程安全
  • 第二个线程调用方法getInstance()的时候,变量s,已经不是null,被前面的线程new过
  • 当已经有对象了,第二个线程没有必要再进入同步了,直接return返回对象即可

单例模式的应用场景和好处

Runtime

任务管理器对象、获取运行时对象

使用单例模式,可以避免资源浪费。

1.3 工厂模式

工厂设计模式,属于创建型,用于对象的创建; 简单来说,就是专门生产对象的

1.3.1 简单工厂模式

java 复制代码
package com.suyv.factory;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 11:26
 * @Description: 动物抽象类
 */
public abstract class Animal {

    public abstract void eat();
}
java 复制代码
package com.suyv.factory;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 11:27
 * @Description: 猫类
 */
public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
java 复制代码
package com.suyv.factory;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 11:28
 * @Description: 狗类
 */
public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}
java 复制代码
package com.suyv.factory;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 11:29
 * @Description: 工厂设计类,这个类就是专门来生产对象,今后从这个工厂类中可以直接获取类对象
 */
public class AnimalFactory {

    private AnimalFactory(){}

    public static Dog createDog(){
        return new Dog();
    }

    public static Cat creatCat(){
        return new Cat();
    }


}
java 复制代码
package com.suyv.factory;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 11:32
 * @Description: 工厂模式测试
 */
public class AnimalTest {

    public static void main(String[] args) {

        // 工厂设计模式:
        //     优点:我可以直接通过工厂来获取对象
        //     缺点:如果要加对象,需要修改工厂类,不便于后期的维护

        // 使用工厂模式创建对象
        Cat cat = AnimalFactory.creatCat();
        Dog dog = AnimalFactory.createDog();

        // 调用方法
        cat.eat();
        dog.eat();
    }
}

1.3.2 实例工厂模式

java 复制代码
package com.suyv.factory1;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 12:11
 * @Description: 创建一个接口
 */
public interface Product {
    public void doSomething();
}
java 复制代码
package com.suyv.factory1;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 12:12
 * @Description: 实现接口的实现类
 */
public class ConcreteProduct implements Product{
    @Override
    public void doSomething() {
        System.out.println("Doing something in ConcreteProduct");
    }
}
java 复制代码
package com.suyv.factory1;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 12:14
 * @Description: 实例工厂类
 */
public class ProductFactory {
    public Product createProduct(){
        return new ConcreteProduct();
    }

}
java 复制代码
package com.suyv.factory1;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 12:15
 * @Description: 实例工厂测试类
 */
public class ProductTest {

    public static void main(String[] args) {
        ProductFactory factory = new ProductFactory();

        Product product = factory.createProduct();

        product.doSomething();
    }
}

1.3.3 静态工厂模式

java 复制代码
package com.suyv.staticfactory;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 12:21
 * @Description: 定义一个咖啡类
 */
public abstract class Coffee {

    public abstract String getName();

    //加糖
    public void addsugar() {
        System.out.println("加糖");
    }

    //加奶
    public void addMilk() {
        System.out.println("加奶");
    }
}
java 复制代码
package com.suyv.staticfactory;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 12:22
 * @Description: 美式咖啡
 */
public class AmericanCoffee extends Coffee{
    @Override
    public String getName() {
        return "美式咖啡";
    }
}
java 复制代码
package com.suyv.staticfactory;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 12:23
 * @Description: 拿铁咖啡
 */
public class LatteCoffee extends Coffee{
    @Override
    public String getName() {
        return "拿铁咖啡";
    }
}
java 复制代码
package com.suyv.staticfactory;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 12:29
 * @Description: 咖啡工厂类--静态工厂
 */
public class SimpleCoffeeFactory {

    public static Coffee createCoffee(String type) {
        //声明Coffee类型的变量,根据不同类型创建不同的coffee子类对象
        Coffee coffee = null;
        if("american".equals(type)) {
            coffee = new AmericanCoffee();
        } else if("latte".equals(type)) {
            coffee = new LatteCoffee();
        } else {
            throw new RuntimeException("对不起,您所点的咖啡没有");
        }

        return coffee;
    }
}
java 复制代码
package com.suyv.staticfactory;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 12:24
 * @Description: 咖啡店类
 */
public class CoffeeStore {

    public Coffee orderCoffee(String type) {

        Coffee coffee = SimpleCoffeeFactory.createCoffee(type);

        //加配料
        coffee.addMilk();
        coffee.addsugar();

        return coffee;
    }
}
java 复制代码
package com.suyv.staticfactory;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 12:26
 * @Description: 静态工厂类测试
 */
public class CofferTest {
    public static void main(String[] args) {

        //创建咖啡店类对象
        CoffeeStore store = new CoffeeStore();
        Coffee coffee = store.orderCoffee("latte");

        System.out.println(coffee.getName());
    }
}

1.4 模板设计模式

模版方法模式,简称为模板设计模式,它主要思想是:把通用的代码生成一个模板,可以反复的使用

java 复制代码
package com.suyv.template;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 14:00
 * @Description: 创建一个模板类
 */
public abstract class GetTime {

    /**
     * @description: 获取一段程序的运行时间
     * @author: 憨憨浩浩
     * @date: 2023/12/27 14:02
     * @param: []
     * @return: long
     **/
    public long getTime(){

        long start = System.currentTimeMillis();

        // 程序
        code();

        long end = System.currentTimeMillis();

        return end - start;
    }

    public abstract void code();

}
java 复制代码
package com.suyv.template;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 14:03
 * @Description: 用户使用模板类
 */
public class ForDemo extends GetTime{
    @Override
    public void code() {
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
        }
    }
}
java 复制代码
package com.suyv.template;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 14:04
 * @Description: 模板设计模式测试类
 */
public class TemplateTest {
    public static void main(String[] args) {
        ForDemo forDemo = new ForDemo();

        System.out.println(forDemo.getTime() + "毫秒");
    }
}

1.5 装饰设计模式

装饰设计模式: 增强原有对象的功能

原本有一个对象,但是这个对象的功能不够强,采用装饰设计模式,对原对象中功能进行增强

回想一下我们当时讲的缓冲流,其实就是装饰设计模式

java 复制代码
package com.suyv.decorate;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 14:09
 * @Description: TODO
 */
public class Phone {
    public void call(){
        System.out.println("手机打电话功能!");
    }
}
java 复制代码
package com.suyv.decorate;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 14:10
 * @Description: TODO
 */
public class SendMsg {
    private Phone phone;

    public SendMsg(Phone phone) {
        this.phone = phone;
    }

    //增强原有手机的功能
    public void msg(){
        System.out.println("发彩信");
        System.out.println("发短信");
        phone.call();
    }
}
java 复制代码
package com.suyv.decorate;

/**
 * @Author: 憨憨浩浩
 * @CreateTime: 2023-12-27 14:11
 * @Description: TODO
 */
public class PhoneTest {
    public static void main(String[] args) {

        SendMsg sendMsg = new SendMsg(new Phone());

        sendMsg.msg();

    }
}

2、面向对象思想设计原则

面向对象思想设计原则

在实际的开发中,我们要想更深入的了解面向对象思想,就必须熟悉前人总结过的面向对象的思想的设计原则

  • 单一职责原则
  • 开闭原则
  • 里氏替换原则
  • 依赖注入原则
  • 接口分离原则
  • 迪米特原则

2.1 单一职责原则

其实就是开发人员经常说的"高内聚,低耦合"

也就是说,每个类应该只有一个职责,对外只能提供一种功能,而引起类变化的原因应该只有一个。在设计模式中,所有的设计模式都遵循这一原则。能自己完成的事就不要麻烦别人,把一件事细化细化,只做一件事情

能自己完成的事就不要麻烦别人,把一件事细化细化,只做一件事情

2.2 开闭原则 ocp

核心思想是:一个对象对扩展开放,对修改关闭。

其实开闭原则的意思就是:对类的改动是通过增加代码进行的,而不是修改现有代码。

也就是说软件开发人员一旦写出了可以运行的代码,就不应该去改动它,而是要保证它能一直运行下去,如何能够做到这一点呢?这就需要借助于抽象和多态,即把可能变化的内容抽象出来,从而使抽象的部分是相对稳定的,而具体的实现则是可以改变和扩展的

2.3 里氏替换原则

核心思想:在任何父类出现的地方都可以用它的子类来替代。

其实就是说:同一个继承体系中的对象应该有共同的行为特征。

2.4 依赖注入原则

核心思想:要依赖于抽象,不要依赖于具体实现。

其实就是说:在应用程序中,所有的类如果使用或依赖于其他的类,则应该依赖这些其他类的抽象类,而不是这些其他类的具体类。为了实现这一原则,就要求我们在编程的时候针对抽象类或者接口编程,而不是针对具体实现编程。

2.5 接口分离原则

核心思想:不应该强迫程序依赖它们不需要使用的方法。

其实就是说:一个接口不需要提供太多的行为,一个接口应该只提供一种对外的功能,不应该把所有的操作都封装到一个接口中。

2.6 迪米特原则

核心思想:一个对象应当对其他对象尽可能少的了解

其实就是说:降低各个对象之间的耦合,提高系统的可维护性。在模块之间应该只通过接口编程,而不理会模块的内部工作原理,它可以使各个模块耦合度降到最低,促进软件的复用

相关推荐
Biomamba生信基地3 分钟前
R语言基础| 时间序列分析
开发语言·r语言·kotlin·编程
Promising_GEO4 分钟前
使用R语言绘制简单地图的教程
开发语言·python·r语言
微尘86 分钟前
C++条件编译指令:#if、#elif、#ifdef、#ifndef、#elifdef、#elifndef、#else、#endif
开发语言·c++
许乌有7 分钟前
matlab基础使用
开发语言·matlab
湫ccc1 小时前
《Python基础》之函数的用法
开发语言·python
G丶AEOM1 小时前
Redis与MySQL如何保证数据一致性
java·redis
lly2024061 小时前
C# 类(Class)
开发语言
梦深时有鹿1 小时前
C#基础练习61-65
开发语言·c#
北漂编程小王子1 小时前
maven <scope>compile</scope>作用
java·maven·compile标签作用
张声录11 小时前
使用client-go在命令空间test里面对pod进行操作
开发语言·后端·golang