文章目录
1. 单例模式*
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点
单例模式使用的场景:需要频繁创建和销毁或创建时耗费资源过多,但又经常用到的对象
1.1 饿汉式(静态常量)
java.lang.Runtime就采用了饿汉式单例模式
饿汉式(静态常量/静态代码块):
- 优点:这种方式基于classloder机制,在类加载时就完成了单例的实例化,避免了线程同步问题
- 缺点:如果从始至终从未使用过这个实例,则会造成内存的浪费
// 饿汉式(静态常量)
public class Singleton {
// 在自己内部定义一个自己的实例
private final static Singleton INSTANCE = new Singleton();
// 私有构造方法(防止new)
private Singleton() {
}
// 提供一个供外部获取对象的静态公共方法
public static Singleton getInstance() {
return INSTANCE;
}
}
1.2 饿汉式(静态代码块)
// 饿汉式(静态代码块)
public class Singleton {
private static Singleton instance;
// 在类加载时,创建单例实例
static {
instance = new Singleton();
}
// 私有构造方法(防止new)
private Singleton() {
}
// 提供一个供外部获取对象的静态公共方法
public static Singleton getInstance() {
return instance;
}
}
1.3 懒汉式(线程安全,同步方法)-
懒汉式:全局的单例实例在需要时再构建(不推荐)
// 懒汉式(线程安全,同步方法)
public class Singleton {
// 在自己内部定义一个自己的实例
private static Singleton instance;
// 私有构造方法(防止new)
private Singleton() {
}
// 提供一个供外部获取对象的静态公共方法,当第一次使用该方法时,再去创建单例实例
// 同步效率太低:每个线程在执行getInstance()时都要同步,
// 但getInstance()只需在第一次使用创建单例对象时需要同步
public static synchronized Singleton getInstance() {
// 避免了多线程时,一个线程进入了if (instance == null),
// 还未来得及往下执行,另一个线程也通过了这个判断语句而产生多个实例
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
1.4 双重检查
// 双重检查
public class Singleton {
// 在自己内部定义一个自己的实例
// 使用volatile防止创建对象时的重排序
private static volatile Singleton instance;
// 私有构造方法(防止new)
private Singleton() {
// 以双重检查为例,防止暴力反射破解单例模式
if (instance != null)
throw new RuntimeException("防止暴力反射破解单例模式");
}
// 提供一个供外部获取对象的静态公共方法
// 使用双重检查,解决了线程安全问题和懒加载问题
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
1.5 静态内部类
// 静态内部类
public class Singleton {
// 在静态内部类中创建单例实例:在第一次使用到SingletonInstance类时,才会加载该类
// 解决了线程安全问题和懒加载问题
private static class SingletonInstance {
private final static Singleton INSTANCE = new Singleton();
}
// 私有构造方法(防止new)
private Singleton() {
}
// 提供一个供外部获取对象的静态公共方法
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
1.6 枚举
// 枚举:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
public enum Singleton {
INSTANCE;
public void method() {
System.out.println("枚举实现单例模式");
}
}
class SingletonClient {
public static void main(String[] args) {
Singleton singleton1 = Singleton.INSTANCE;
Singleton singleton2 = Singleton.INSTANCE;
System.out.println(singleton1 == singleton2);
singleton1.method();
/**
* 结果:
* true
* 枚举实现单例模式
*/
}
}
2. 工厂方法模式*
2.1 简单工厂模式
简单工厂模式又叫做静态工厂方法模式,但不属于23种设计模式之一
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例
由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,因此一般只在工厂类负责创建的对象比较少的情况下应用
java.util.Calendar类就使用了简单工厂模式
// 抽象产品
interface Animal {
}
// 具体产品
class Dog implements Animal {
}
// 具体工厂:简单工厂模式的核心
class AnimalFactory {
public static Animal createAnimal(String type) {
switch (type) {
case "Dog":
return new Dog();
default:
return null;
}
}
}
public class StaticFactoryMethodClient {
public static void main(String[] args) {
Animal dog = AnimalFactory.createAnimal("Dog");
// true
System.out.println(dog instanceof Dog);
}
}
2.2 工厂方法模式
工厂方法模式的意义:定义一个用于创建对象的接口,让子类决定实例化哪一个类
工厂方法模式中存在四种角色:
- 抽象产品:产品对象的共同父类或共同拥有的接口
- 具体产品:这个角色实现了抽象产品角色所定义的接口
- 抽象工厂:任何在模式中创建对象的工厂类必须实现这个接口
- 具体工厂:实现抽象工厂接口的具体工厂类
工厂方法模式是模板方法模式的应用
// 抽象产品
interface Animal {
}
// 具体产品
class Dog implements Animal {
}
// 抽象工厂:工厂方法模式的核心
interface AnimalFactory {
Animal createAnimal();
}
// 具体工厂
class DogFactory implements AnimalFactory {
@Override
public Animal createAnimal() {
return new Dog();
}
}
public class FactoryMethodClient {
public static void main(String[] args) {
DogFactory dogFactory = new DogFactory();
Animal dog = dogFactory.createAnimal();
// true
System.out.println(dog instanceof Dog);
}
}
3. 抽象工厂模式
抽象工厂模式:提供一个接口以创建一系列相关或相互依赖的对象,而无须指定它们具体的类
工厂方法模式是一个产品系列一个工厂类,而抽象工厂模式是多个产品系列一个工厂类
抽象工厂模式解决的问题是当涉及到有多个产品等级结构时,如何更好地进行软件体系结构的设计
// 抽象产品:动物
interface Animal {
}
// 抽象产品:植物
interface Plant {
}
// 具体产品:中国动物
class ChinaAnimal implements Animal {
}
// 具体产品:中国植物
class ChinaPlant implements Plant {
}
// 具体产品:美国动物
class AmericaAnimal implements Animal {
}
// 具体产品:美国植物
class AmericaPlant implements Plant {
}
// 抽象工厂:抽象工厂模式的核心
interface Factory {
Animal createAnimal();
Plant createPlant();
}
// 具体工厂:中国工厂
class ChinaFactory implements Factory {
@Override
public Animal createAnimal() {
return new ChinaAnimal();
}
@Override
public Plant createPlant() {
return new ChinaPlant();
}
}
// 具体工厂:美国工厂
class AmericaFactory implements Factory {
@Override
public Animal createAnimal() {
return new AmericaAnimal();
}
@Override
public Plant createPlant() {
return new AmericaPlant();
}
}
public class AbstractFactoryClient {
public static void main(String[] args) {
Factory chinaFactory = new ChinaFactory();
Factory americaFactory = new AmericaFactory();
System.out.println(chinaFactory.createAnimal() instanceof ChinaAnimal);
System.out.println(chinaFactory.createPlant() instanceof ChinaPlant);
System.out.println(americaFactory.createAnimal() instanceof AmericaAnimal);
System.out.println(americaFactory.createPlant() instanceof AmericaPlant);
}
}
4. 原型模式
原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
原型模式主要解决的问题是:“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口
缺点:需要给类配备一个克隆方法,对已有的类需要修改其源代码,违背了开闭原则
原型模式:在原型中自带一个拷贝方法
import lombok.Data;
import java.io.Serializable;
// 重写Object的clone()方法需要实现Cloneable接口
@Data
public class Prototype implements Serializable, Cloneable {
String attribute;
// 默认super.clone()浅拷贝:对象中的值类型成员变量拷贝值,引用类型成员变量仅拷贝引用
@Override
protected Object clone() {
Object obj = null;
try {
obj = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return obj;
}
}
深拷贝:
import lombok.Data;
import java.io.*;
@Data
public class DeepCopy implements Serializable, Cloneable {
String value;
Prototype prototype;
// 重写clone()深拷贝:对象中的值类型成员变量拷贝值,引用类型成员变量拷贝整个引用对象
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = null;
// 对值类型进行拷贝
obj = super.clone();
// 对引用类型进行拷贝
((DeepCopy) obj).prototype = (Prototype) prototype.clone();
return obj;
}
// 对象序列化深拷贝*:对象中的值类型成员变量拷贝值,引用类型成员变量拷贝整个引用对象
public Object deepCloneBySerializable() {
Object obj = null;
ByteArrayOutputStream baos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bais = null;
ObjectInputStream ois = null;
try {
// 序列化
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(this);
// 反序列化
bais = new ByteArrayInputStream(baos.toByteArray());
ois = new ObjectInputStream(bais);
obj = ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bais.close();
ois.close();
baos.close();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return obj;
}
}
5. 建造者模式*
建造者模式(生成器模式):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
建造者模式中有以下几个角色:
- 产品Product:表示被构造的复杂对象
- 抽象建造者Builder:为创建一个产品对象的各个部件指定抽象接口
- 具体建造者ConcreteBuilder:实现Builder的接口,构造和装配该产品的各个部件
- 指导者Director:构造一个使用Builder接口的对象,它负责控制产品对象的生产过程,隔离了客户与对象的生产过程
建造者模式在使用过程中可以演化出多种形式,如:
- 省略抽象建造者角色
- 省略指导者角色
java.lang.StringBuilder的append方法使用的就是建造者模式
import lombok.Data;
// 产品
@Data
class Product {
String inner;
String outer;
}
// 抽象建造者:抽象出建造过程
interface Builder {
void buildInner();
void buildOuter();
Product buildProduct();
}
// 具体建造者:不同产品,创建不同的具体建造者
class ConcreteBuilder implements Builder {
Product product;
public ConcreteBuilder(Product product) {
this.product = product;
}
@Override
public void buildInner() {
product.inner = "建造产品内部";
}
@Override
public void buildOuter() {
product.outer = "建造产品外部";
}
@Override
public Product buildProduct() {
return product;
}
}
// 指导者:根据建造过程组装产品
class Director {
public Product constructProduct(Builder builder) {
builder.buildInner();
builder.buildOuter();
return builder.buildProduct();
}
}
public class BuilderClient {
public static void main(String[] args) {
ConcreteBuilder concreteBuilder = new ConcreteBuilder(new Product());
Director director = new Director();
Product product = director.constructProduct(concreteBuilder);
// Product(inner=建造产品内部, outer=建造产品外部)
System.out.println(product);
}
}