Java的设计模式

本文介绍了设计模式中的单例模式,包括饿汉式和懒汉式的实现及其优缺点,以及如何通过枚举优化单例的安全性和简洁性。此外,还讲解了工厂模式,包括简单工厂和工厂方法模式,以及它们在扩展性和代码解耦方面的考量。最后提到了建造者模式,用于创建复杂对象的构建过程与表示分离。
摘要由CSDN通过智能技术生成

1. 设计模式概述

是前辈对代码开发经验的总结,是解决特定问题的一系列套路。不是语法规定,而是一套用来提高代码可复用性,可维护性,可读性,稳健性以及安全性的解决方案

创建型模式:使对象的创建与使用分离

单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式

结构型模式:如何将类或者对象按照某种布局组成一种更大的结构

适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式

行为型模式:描述类或者对象之间如何相互协作完成单个对象无法完成的任务

模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式

2. OOP七大原则

开闭原则:对扩展开放,对修改关闭

里氏替换原则:继承必须确保超类所拥有的性质在子类中仍然成立

依赖倒置原则:要面向接口变成,不要面向实现编程

单一职责原则:控制类的粒度大小,将对象解耦,提高其内聚性

接口隔离原则:要为各个类建立它们需要的专用接口

迪米特原则:只与你的直接朋友交谈,不跟”陌生人“说话

合成复用原则:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现

3. 单例模式

在内存中只会创建且仅创建一次对象的设计模式。

在程序中多次使用同一个对象且作用相同时,为了防止频繁创建对象使内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象。
在这里插入图片描述

1.饿汉式单例

饿汉式单例在类加载时已经创建好对象(private static final Hungry HUNGRY = new Hungry()),程序调用时直接返回该单例对象即可

package com.itwrj.single;

// 饿汉式单例
public class Hungry {
    //可能会浪费空间
    private byte[] date1 = new byte[1024*1024];
    //单例模式最重要的特征:构造器私有
    private Hungry() {

    }
    //一上来就把对象加载
    private static final Hungry HUNGRY = new Hungry();

    //对外的方法
    public static Hungry getInstance(){
        return HUNGRY;
    }
}

public class Hungry{
    private Hungry(){}
    private static final Hungry HUNGRY = new Hangry();
    public static Hungry getInstance(){
        return HUNGRY;
    }
}

2.懒汉式单例

在真正需要使用时才去创建单例对象

创建方法:在程序使用对象前,先判断该对象是否已经实例化(判空),如果已经实例化则返回该对象,否则先执行实例化操作

public class LazyMan{

	private LazyMan(){
	
	}
	
	private volatile static LazyMan lazyman;
	//双重检测锁模式的懒汉式单例 即DCL懒汉式
	public static LazyMan getInstance(){
		if(lazyman==null){
			synchronized(LazyMan.class){
				if(lazyman==null){
					lazyman = new LazyMan();
				}
			}
		}
		return lazyman;
	}
}

public static LazyMan{
    private LazyMan(){}
    private volatile static LazyMan lazyman;
    if(lazyman==null){
        synchroniezd(LazyMan.class){
            if(lazyman==null){
                lazyman=new LazyMan();
            }
        }
    }
    return lazyman;
    }
}

Q1:但是在多线程下是不安全

比如有两个线程同时判断lazyman==null,那么他们都会去实例化一个对象,这个时候就变成了双例

Q2 :可以想到在方法上或者代码块上加锁,但是每次获取对象时都需要先获取锁,并发性能很差。

因此,可以在获取锁前判断是否已经实例化,如果没有实例化则加锁,否则直接获取对象

Q3:但是创建对象并非原子性操作,而是有3个步骤。在创建对象时可能发生指令重排,即可能以132的步骤创建对象,当A执行1、3步骤时,如果另个一个线程B判断lazyman不为空,就会返回对象,但是此时的对象是未初始化的对象,就会发生错误。

lazyman = new LazyMan();

1.分配内存空间

2.执行构造方法,初始化对象

3.把这个对象指向内存空间

因此,可以使用volatile关键字防止指令重排

volatile关键字的作用

1.防止指令重排

2.使用volatile修饰的变量,可以保证内存的可见性,即每一时刻线程读取到该变量的 值都是内存中最新的那个值,线程每次操作该变量都需要先读取该变量

3.破坏饿汉式单例懒汉式单例

反射和序列化 会破坏单例对象,产生多个对象

4.使用枚举实现单例模式

jdk1.5之后有了枚举

public enum EnumSingle{
    INSTANCE;
    
    public EnumSingle getInstance(){
        return INSTANCE;
    }
}

public enum EnumSingle{
    INSTANCE;
    
    public EnumSingle getInstance(){
        return INSTANCE;
    }
}

优势:

1.代码更加简洁

2.不需要任何额外的操作去保证对象单一性和线程安全性

3.可以防止反射、序列化与反序列化抢占生成多个对象

5.总结

1.单例模式常见写法有:饿汉式和懒汉式

2.饿汉式:在类加载时已经创建好了对象,在获取对象时直接返回该对象即可,不会存在安全性和并发问题

3.懒汉式:在需要时才实例化单例对象,需要双重验证和锁,解决并发问题

4.在开发中如果对内存要求很高,使用懒汉式写法,在需要时才创建对象

5.如果对内存要求不高,使用饿汉式写法,简单不易出错且没有安全性问题

6.懒汉式单例下,为了防止创建对象发生指令重排报NPE,在变量上加volatile关键字,防止指令重排序

7.最好的方式是枚举,代码精简没有安全性问题且可以防止反射、序列化和反序列化破坏单例模式

4.工厂模式

作用:创建者和调用者分离

核心本质:

1.实例化对象不使用new,用工厂方法代替

2.将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦

一般模式

我们需要自己去new对象,然后使用

需要Car接口,Wuling实现类,Tesla实现类

//Car接口
package com.itwrj.factory.simple;

public interface Car {
    void name();
}
//Wuling实现类
package com.itwrj.factory.simple;

public class Wuling implements Car{
    @Override
    public void name() {
        System.out.println("五菱宏光");
    }
}
//Tesla实现类
package com.itwrj.factory.simple;

public class Tesla implements Car{
    @Override
    public void name() {
        System.out.println("特斯拉");
    }
}

package com.itwrj.factory.simple;

public class Consumer {
    public static void main(String[] args) {
        //接口、实现类都需要知道 相当于自己造车出来
        Car car = new Wuling();
        Car car1 = new Tesla();

        car.name();
        car1.name();
    }
}

1.简单工厂模式/静态工厂模式

用来生产同一等级结构中的任意产品(对于增加新的产品,需要球盖已有代码)

简单工厂模式下,可以自己创建一个车工厂,只需要传给他一个String类型的名字

package com.itwrj.factory.simple;

//车工厂,只需要传给他一个String类型的名字
public class CarFactory {
    public static Car getCar(String car){
        if (car.equals("五菱宏光")){
            return new Wuling();
        }else if (car.equals("特斯拉")){
            return new Tesla();
        }else {
            return null;
        }
    }
}
package com.itwrj.factory.simple;

public class Consumer {
    public static void main(String[] args) {
        //接口、实现类都需要知道 相当于自己造车出来
        //Car car = new Wuling();
        //Car car1 = new Tesla();

        //使用工厂创建
        Car car = CarFactory.getCar("五菱宏光");
        Car car1 = CarFactory.getCar("特斯拉");

        car.name();
        car1.name();
    }
}

优点:

用专门的工厂类创建对象,不用关心对象的具体细节,提高了灵活性

缺点:

当需要添加新产品时,需要修改工厂类的代码,不满足开闭原则(对扩展开放,对修改关闭)

在这里插入图片描述

2.工厂方法模式

用来生产同一等级结构中的固定产品(支持增加任意产品)

//类接口
public interface Car {
    void name();
}
//Tesla类
public class Tesla implements Car{
    @Override
    public void name() {
        System.out.println("特斯拉");
    }
}
//Wuling类
public class Wuling implements Car {
    @Override
    public void name() {
        System.out.println("五菱宏光");
    }
}
//Dazhong类
public class Dazhong implements Car{
    @Oberride
    public void name() {
        sout("大众");
    }
}

//创建对象的接口
public interface CarFactory {
    Car getCar();
}
//Tesla工厂类,决定实例化的对象
public class TeslaFactory implements CarFactory {

    @Override
    public Car getCar() {
        return new Tesla();
    }
}
//Wuling工厂类,决定实例化的对象
public class WulingFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new Wuling();
    }
}
//Dazhong工厂类,决定实例化的对象
public class DazhongFactory implements CarFactory{
    @Override
    public Car getCar(){
        return new Dazhong();
    }
}


image-20230416211602806

优点:

将工厂抽象化,定义一个创建对象的接口。每次新增产品,只需要增加该产品以及对应的实现工厂类。由具体的工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,就符合开闭原则(对扩展开放,对修改关闭),扩展时不必修改原来的代码

缺点:

新增产品需要增加对于的产品类和实现工厂类,导致类比较多,结果庞大

简单工厂VS工厂方法

结构复杂度:simple<method

代码复杂度:simple<method

编程复杂度:simple<method

管理复杂度:simple<method

根据设计原则:method 因为满足开闭原则

根据实际业务:simple 因为更简单

image-20230416212200991

3.抽象工厂模式

围绕一个超级工厂创建其他工厂。该超级工程又称为其他工厂的工厂

生产工厂的工厂

定义:提供了一个创建一系列相关或者相互依赖对象的接口,无需指定他们具体的类

适用场景:

1.客户端(应用层)不依赖于产品类实例如何被创建、实现等细节

2.强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量的代码复用

3.提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体的实现

产品等级:比如华为手机和小米手机

产品族:比如小米手机和小米路由器;华为手机和华为路由器

手机产品接口 路由器产品接口 小米手机类 小米路由器类 华为手机类 华为路由器类

产品工厂接口(包含手机工厂和路由器工厂)(超级工厂) 华为工厂 小米工厂 客户端

超级工厂是产品工厂(IProductFactory 接口) 用来创建小米工厂(XiaomiFactory 实现类)和华为工厂(HuaweiFactory实现类) 小米工厂需要创建小米手机(XiaomiIphone实现类)和小米路由器(XiaomiIRouter实现类) 小米手机的创建需要手机接口(IPhoneProduct 接口) 小米路由器的创建需要路由器接口(RouterProduct 接口)

优点:

1.具体的产品在应用层的代码隔离,无需关心创建细节

2.将一个系列的产品统一到一起创建

缺点:

1.规定了所有可能会被创建的产品集合,产品族中扩展新的产品困难

2.增加了系统的抽象性和理解难度

4.小结

简单工厂模式:

虽然某种程度上不符合设计原则,但实际用的多

工厂方法模式:

不修改已有类的前提下,通过增加新的工厂类实现扩展

抽象工厂模式:

不可以增加产品,可以增加产品族

应用场景:

1.JDK中Calender的getInstance方法

2.JDBC中的Connection对象的获取

3.Spring中IOC容器创建管理bean对象

4.反射中Class对象的newInstance方法

5. 建造者模式

提供一种创建对象的最佳方式。

定义:

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

作用:

在用户不知道对象的建造过程和细节的情况下就可以直接创建出复杂的对象

//产品(具体的房子)要创建的产品对象
public class Product {

    private String buildA;
    private String buildB;
    private String buildC;
    private String buildD;

    public String getBuildA() {
        return buildA;
    }

    public void setBuildA(String buildA) {
        this.buildA = buildA;
    }

    public String getBuildB() {
        return buildB;
    }

    public void setBuildB(String buildB) {
        this.buildB = buildB;
    }

    public String getBuildC() {
        return buildC;
    }

    public void setBuildC(String buildC) {
        this.buildC = buildC;
    }

    public String getBuildD() {
        return buildD;
    }

    public void setBuildD(String buildD) {
        this.buildD = buildD;
    }

    @Override
    public String toString() {
        return "Product{" +
                "buildA='" + buildA + '\'' +
                ", buildB='" + buildB + '\'' +
                ", buildC='" + buildC + '\'' +
                ", buildD='" + buildD + '\'' +
                '}';
    }
}
//抽象的建造者,不负责造房子,而是定义一些方法和接口
public abstract class Builder {
    abstract void buildA(); //地基
    abstract void buildB(); //钢筋水泥
    abstract void buildC(); //铺线
    abstract void buildD(); //粉刷

    abstract Product getProduct();
}
//具体的建造者 根据不同的业务逻辑,具体化对象各个部分的组建
public class Worker extends Builder {

    private Product product;

    public Worker() {
        product = new Product();
    }

    @Override
    void buildA() {
        product.setBuildA("地基");
        System.out.println("地基");
    }

    @Override
    void buildB() {
        product.setBuildB("钢筋水泥");
        System.out.println("钢筋水泥");
    }

    @Override
    void buildC() {
        product.setBuildC("铺线");
        System.out.println("铺线");
    }

    @Override
    void buildD() {
        product.setBuildD("粉刷");
        System.out.println("粉刷");
    }

    @Override
    Product getProduct() {
        return product;
    }
}
//指挥:是核心 负责指挥构建一个工程,工程如何构建由他决定
public class Director {

    //指挥工人按照顺序建房子
    public Product build(Builder builder){
        builder.buildA();
        builder.buildB();
        builder.buildC();
        builder.buildD();

        return builder.getProduct();
    }
}
public class Test {
    public static void main(String[] args) {
        //指挥
        Director director = new Director();
        //指挥 实体的工人完成产品
        Product build = director.build(new Worker());
        System.out.println(build.toString());
    }
}

public static void main(String[] args) {
        //指挥
        Director director = new Director();
        //指挥 实体的工人完成产品
        Product build = director.build(new Worker());
        System.out.println(build.toString());
    }
}
1) 优秀的程序应该是这样的:阅读时,感觉很优雅;新增功能时,感觉很轻松;运行时,感觉很快速,这就需要设计模式支撑。2) 设计模式包含了大量的编程思想,讲授和真正掌握并不容易,网上的设计模式课程不少,大多讲解的比较晦涩,没有真实的应用场景和框架源码支撑,学习后,只知其形,不知其神。就会造成这样结果: 知道各种设计模式,但是不知道怎么使用到真实项目。本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,比如 单例模式的8种实现方式、工厂模式的3种实现方式、适配器模式的3种实现、代理模式的3种方式、深拷贝等3) 如果你想写出规范、漂亮的程序,就花时间来学习下设计模式吧课程内容和目标本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式1) 内容包括: 设计模式七大原则(单一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML类图(类的依赖、泛化和实现、类的关联、聚合和组合) 23种设计模式包括:创建型模式:单例模式(8种实现)、抽象工厂模式、原型模式、建造者模式、工厂模式。结构型模式:适配器模式(3种实现)、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式(3种实现)。行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)2) 学习目标:通过学习,学员能掌握主流设计模式,规范编程风格,提高优化程序结构和效率的能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值