1.单例模式
-
单例模式能够保证一个类只有一个实例,并且提供一个可以访问该实例的全局节点
-
实现步骤
- 类中添加一个私有静态成员变量用于保存单例实例
- 声明一个公有静态构建方法用于获取单例实例
- 在静态方法中实现"延迟初始化"。 该方法会在首次被调用时创建一个新对象, 并将其存储在静态成员变量中。 此后该方法每次被调用时都返回该实例
- 将类的构造函数设为私有。 类的静态方法仍能调用构造函数, 但是其他对象不能调用
- 检查客户端代码, 将对单例的构造函数的调用替换为对其静态构建方法的调用
-
优点与缺点
-
优点
- 保证一个类只有一个实例
- 首次请求单例对象时对其进行初始化
-
缺点
- 违反单一职责(保证一个类只能有一个实例,又提供可以访问该实例的全局节点)
- 多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象
-
-
实现方式
// 1.懒汉式 public class HungrySingleton { // 类的构造函数设为私有 private HungrySingleton() { } // 方式一直接声明 // public static HungrySingleton hungrySingleton = new HungrySingleton(); // 方式二通过静态代码块 private static HungrySingleton hungrySingleton ; static { hungrySingleton = new HungrySingleton(); } // 声明一个公有静态构建方法用于获取单例实例 public static HungrySingleton getHungrySingleton(){ return hungrySingleton; } } // 2.饿汉式 public class LazySingleton { private LazySingleton() { } // volatile防止指令重排 多线程情况下 先分配地址然后再初始化导致获取的实例对象为null private static volatile LazySingleton lazySingleton; public static LazySingleton getLazySingleton() { // 双重检查机制 if (lazySingleton == null) { synchronized (LazySingleton.class){ if (lazySingleton == null){ lazySingleton = new LazySingleton(); } return lazySingleton; } } return lazySingleton; } } // 3.静态内部类 public class StaticInnerClassSingleton { private StaticInnerClassSingleton() {} /* 类里面所有的类变量的赋值动作和静态代码块组成的<clinit>方法 多线程情况下只会有一个线程去执行<cinit>方法,其他线程被唤醒,不会再进入<clinit>()方法。也就是说同一个加载器下,一个类型只会初始化一次。 因为有指令重排序也不会影响到其它线程 */ public static class SingletonHolder { private static final StaticInnerClassSingleton singleton= new StaticInnerClassSingleton(); } public static StaticInnerClassSingleton getStaticInnerClassSingleton(){ return SingletonHolder.singleton; } } // 4.枚举方式 public enum SingletonEnum { /* 线程安全且只会装载一次、饿汉式、单例模式中唯一一种不会被破坏的单例实现模式 */ INSTANCE; }
-
破坏单例模式
-
序列化
public class StaticInnerClassSingleton implements Serializable { private StaticInnerClassSingleton() {} public static class SingletonHolder { private static final StaticInnerClassSingleton singleton= new StaticInnerClassSingleton(); } public static StaticInnerClassSingleton getStaticInnerClassSingleton(){ return SingletonHolder.singleton; } // 当进行反序列化时,会自动调用该方法,将该方式的返回值直接返回 具体可以追踪源码 public Object readResolver(){ return SingletonHolder.singleton } }
-
反射
public class StaticInnerClassSingleton implements Serializable { private static boolean flag = false; // 解决反射破坏单例模式 private StaticInnerClassSingleton() { synchronized (StaticInnerClassSingleton.class){ if (flag){ throw new RuntimeException("不能创建多个对象"); } flag = true; } } public static class SingletonHolder { private static final StaticInnerClassSingleton singleton= new StaticInnerClassSingleton(); } public static StaticInnerClassSingleton getStaticInnerClassSingleton(){ return SingletonHolder.singleton; } }
-
2.工厂方法模式
- 定义用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类
- 结构
- 抽象工厂:提供创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品
- 具体工厂:实现抽象工厂中的抽象方法,完成具体产品的创建
- 抽象产品:定义了产品的规范,描述了产品的主要特性和功能
- 具体产品:实现抽象产品角色所定义的接口,由具体工厂来创建
-
实现
public abstract class Coffee { public abstract String getName(); public void addMilk(){ System.out.println("添加牛奶"); } public void addSugar(){ System.out.println("添加糖"); } } public class LatteCoffee extends Coffee{ @Override public String getName() { return "拿铁咖啡"; } } public class AmericanCoffee extends Coffee{ @Override public String getName() { return "美式咖啡"; } } public interface CoffeeFactory { Coffee orderCoffee(); } public class AmericanCoffeeFactory implements CoffeeFactory{ @Override public Coffee orderCoffee() { return new AmericanCoffee(); } } public class LatteCoffeeFactory implements CoffeeFactory{ @Override public Coffee orderCoffee() { return new LatteCoffee(); } } public class CoffeeStore { private CoffeeFactory factory; public void setFactory(CoffeeFactory factory){ this.factory = factory; } public Coffee orderCoffee() { return factory.orderCoffee(); } }
-
优点与缺点
- 优点
- 避免创建者和具体产品之间的紧密耦合
- 开闭原则。 无需更改现有客户端代码, 你就可以在程序中引入新的产品类型
- 缺点
- 应用工厂方法模式需要引入许多新的子类, 代码可能会因此变得更复杂(类爆炸)
- 优点
3.抽象工厂模式
-
是一种为访问类提供一个创建一组相关或互相依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同组的不同等级的厂品的模式结构。是工厂模式的升级版本,工厂模式只生产一个等级的产品,而抽象模式可生产多个等级的产品。
-
结构
- 抽象工厂:提供创建产品的接口,包含多个创建产品的方法,可以创建多个不同等级的产品
- 具体工厂:实现抽象工厂中的多个抽象方法,完成具体产品的创建
- 抽象产品:定义产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品
- 具体产品:实现抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一多关系
-
产品和等级的概念
- 装饰风艺术的椅子和沙发和咖啡桌理解为产品(公司下一系列的产品)
- 装饰风、维多利亚、现代的椅子可以理解为等级 (同属于椅子一类)
-
实现
public abstract class Coffee {
public abstract String getName();
public void addMilk(){
System.out.println("添加牛奶");
}
public void addSugar(){
System.out.println("添加糖");
}
}
public class AmericanCoffee extends Coffee {
@Override
public String getName() {
return "美式咖啡";
}
}
public class LatteCoffee extends Coffee{
@Override
public String getName() {
return "拿铁咖啡";
}
}
public abstract class Dessert {
abstract void show();
}
public class MatchMousse extends Dessert{
@Override
void show() {
System.out.println("抹茶慕斯");
}
}
public class Tiramisu extends Dessert{
@Override
void show() {
System.out.println("提拉米苏");
}
}
public interface DessertFactory {
Coffee createCoffee();
Dessert createDessert();
}
public class AmericanDessertFactory implements DessertFactory{
@Override
public Coffee createCoffee() {
return new AmericanCoffee();
}
@Override
public Dessert createDessert() {
return new Tiramisu();
}
}
public class ItalyDessertFactory implements DessertFactory{
@Override
public Coffee createCoffee() {
return new LatteCoffee();
}
@Override
public Dessert createDessert() {
return new MatchMousse();
}
}
-
优点与缺点
-
优点
-
确保同一工厂生成的产品相互匹配
-
避免客户端和具体产品代码的耦合
-
单一职责原则。 你可以将产品生成代码抽取到同一位置, 使得代码易于维护
-
开闭原则。 向应用程序中引入新产品变体时, 你无需修改客户端代码
-
-
缺点
- 由于采用该模式需要向应用中引入众多接口和类, 代码可能会比之前更加复杂
-
4.原型模式
-
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象
-
结构
-
抽象原型类:规定了具体原型对象必须实现clone()方法
-
具体原型类:实现抽象原型类的clone()方法,它是可被复制的对象
-
访问类:使用具体原型类中的clone()方法来复制新的对象
-
-
实现
- 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指的对象的内存地址
- 深克隆:创建一个新对象,属性中引用的其它对象也会被克隆,不再指向原有对象地址
public class Citation implements Cloneable{
private Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public Citation() {
System.out.println("Citation构造器执行了");
}
@Override
protected Citation clone() throws CloneNotSupportedException {
System.out.println("执行浅克隆Citation");
return (Citation) super.clone();
}
public void show (){
System.out.println(student.getName()+"同学在ACM亚洲区域赛获得一等奖,特此表扬!");
}
}
@Data
public class Student {
private String name;
}
public class TestProtype {
public static void main(String[] args) throws CloneNotSupportedException {
Citation citation1 = new Citation();
Student student = new Student();
student.setName("浪浪山");
citation1.setStudent(student);
System.out.println("===========克隆=============");
Citation citation2 = citation1.clone();
citation2.getStudent().setName("林林");
citation1.show();
citation2.show();
}
}
优点与缺点
-
优点
-
克隆对象, 无需与它们所属的具体类相耦合
-
克隆预生成原型, 避免反复运行初始化代码
-
更方便地生成复杂对象
-
开闭原则。 向应用程序中引入新产品变体时, 你无需修改客户端代码
-
-
缺点
- 克隆包含循环引用的复杂对象可能会非常麻烦
5.建造者模式
-
将复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示
-
结构
- 抽象建造者类:规定要实现的复杂对象的那些部分的创建,并不涉及具体的部件对象的创建
- 具体建造者类:完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供产品的实例
- 产品类:创建的复杂对象
- 指挥者类:调用具体建造者来创建复杂对象的各个部分,在指导中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建
-
实现
@Data public class Bike { private String frame; private String seat; } public abstract class Builder { protected Bike bike = new Bike(); // 构建车架 abstract void buildFrame(); // 构建座椅 abstract void buildSeat(); abstract Bike createBike(); } public class MoBikeBuilder extends Builder { @Override void buildFrame() { bike.setFrame("摩拜车架"); } @Override void buildSeat() { bike.setSeat("摩拜座椅"); } @Override Bike createBike() { return bike; } } public class OfoBuilder extends Builder { @Override void buildFrame() { bike.setFrame("ofo车架"); } @Override void buildSeat() { bike.setSeat("ofo座椅"); } @Override Bike createBike() { return bike; } } public class Director { private Builder builder; public Director(Builder builder) { this.builder = builder; } public Bike construct() { builder.buildFrame(); builder.buildSeat(); return builder.createBike(); } }
-
优缺点
- 优点
- 步创建对象,暂缓创建步骤或递归运行创建步骤
- 生成不同形式的产品时,可以复用相同的制造代码
- 单一职责原则, 可以将复杂构造代码从产品的业务逻辑中分离出来
- 缺点
- 由于该模式需要新增多个类, 因此代码整体复杂程度会有所增加
- 优点