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 单例模式饿汉式

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;}}

测试

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@677327b6System.out.println(a2); // com.suyv.singleton.A@677327b6System.out.println(a1 == a2); // true}}

1.2.5 单例模式懒汉式

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;}}

测试

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@677327b6System.out.println(b2); // com.suyv.singleton.B@677327b6System.out.println(b1 == b2); // true}}

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

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

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

1.2.6.2 懒汉式线程安全问题

问题出现:

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;}}
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(){@Overridepublic void run() {b1 = B.getInstance();}};Thread t2 = new Thread(new Runnable() {@Overridepublic 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@677327b6System.out.println(b2); // com.suyv.singleton.B@14ae5a5System.out.println(b1 == b2); // false}}

解决方案:

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;}}
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(){@Overridepublic void run() {b1 = B.getInstance();}};Thread t2 = new Thread(new Runnable() {@Overridepublic 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@677327b6System.out.println(b2); // com.suyv.singleton.B@677327b6System.out.println(b1 == b2); // true}}

解决程线安全问题

双层if判断的原因

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

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

Runtime

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

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

1.3 工厂模式

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

1.3.1 简单工厂模式

package com.suyv.factory;/** * @Author: 憨憨浩浩 * @CreateTime: 2023-12-27 11:26 * @Description: 动物抽象类 */public abstract class Animal {public abstract void eat();}
package com.suyv.factory;/** * @Author: 憨憨浩浩 * @CreateTime: 2023-12-27 11:27 * @Description: 猫类 */public class Cat extends Animal{@Overridepublic void eat() {System.out.println("猫吃鱼");}}
package com.suyv.factory;/** * @Author: 憨憨浩浩 * @CreateTime: 2023-12-27 11:28 * @Description: 狗类 */public class Dog extends Animal{@Overridepublic void eat() {System.out.println("狗吃骨头");}}
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();}}
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 实例工厂模式

package com.suyv.factory1;/** * @Author: 憨憨浩浩 * @CreateTime: 2023-12-27 12:11 * @Description: 创建一个接口 */public interface Product {public void doSomething();}
package com.suyv.factory1;/** * @Author: 憨憨浩浩 * @CreateTime: 2023-12-27 12:12 * @Description: 实现接口的实现类 */public class ConcreteProduct implements Product{@Overridepublic void doSomething() {System.out.println("Doing something in ConcreteProduct");}}
package com.suyv.factory1;/** * @Author: 憨憨浩浩 * @CreateTime: 2023-12-27 12:14 * @Description: 实例工厂类 */public class ProductFactory {public Product createProduct(){return new ConcreteProduct();}}
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 静态工厂模式

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("加奶");}}
package com.suyv.staticfactory;/** * @Author: 憨憨浩浩 * @CreateTime: 2023-12-27 12:22 * @Description: 美式咖啡 */public class AmericanCoffee extends Coffee{@Overridepublic String getName() {return "美式咖啡";}}
package com.suyv.staticfactory;/** * @Author: 憨憨浩浩 * @CreateTime: 2023-12-27 12:23 * @Description: 拿铁咖啡 */public class LatteCoffee extends Coffee{@Overridepublic String getName() {return "拿铁咖啡";}}
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;}}
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;}}
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 模板设计模式

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

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();}
package com.suyv.template;/** * @Author: 憨憨浩浩 * @CreateTime: 2023-12-27 14:03 * @Description: 用户使用模板类 */public class ForDemo extends GetTime{@Overridepublic void code() {for (int i = 0; i < 100; i++) {System.out.println(i);}}}
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 装饰设计模式

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

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

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

package com.suyv.decorate;/** * @Author: 憨憨浩浩 * @CreateTime: 2023-12-27 14:09 * @Description: TODO */public class Phone {public void call(){System.out.println("手机打电话功能!");}}
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();}}
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 迪米特原则

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

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