❄介绍
设计模式是常见的软件设计问题的可重用解决方案。它们提供了一种解决开发人员在设计软件应用程序时经常遇到的问题的方法。设计模式有几种类型,包括创建型、结构型和行为型模式。
- 创建型模式:用于以灵活和高效的方式创建对象。包括Singleton模式、工厂模式和抽象工厂模式等。
- 结构型模式:用于组合类和对象以形成更大的结构。包括适配器模式、桥接模式和装饰器模式等。
- 行为型模式:用于处理类或对象之间的通信和控制流。包括观察者模式、策略模式和模板方法模式。
❄六大原则
- 单一职责原则(SRP):一个类只应该有一个引起它变化的原因。
- 开放封闭原则(OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。
- 里氏替换原则(LSP):子类型必须能够替换掉它们的父类型。
- 依赖倒置原则(DIP):高层模块不应该依赖于低层模块,两者都应该依赖于抽象接口;抽象接口不应该依赖于具体实现,具体实现应该依赖于抽象接口。
- 接口隔离原则(ISP):不应该强迫一个类实现它不需要的接口,应该将接口拆分成更小和更具体的部分,以便客户端只需要知道它们感兴趣的部分。
- 迪米特法则(LOD):一个对象应该对其他对象有尽可能少的了解,通常称为“最少知识原则”。
❄1·创建型模式
1.1·单例模式
单例模式(Singleton Pattern)是Java中最简单的设计模式之一,具有遵循以下特点:
- 单例类只能有一个实例;
- 单例类必须自己创建自己的唯一实例;
- 单例类必须为其他对象提供这一实例;
1.1.1·饿汉式
/**
* 单例模式:饿汉式
* 优点:没有加锁,执行效率会提高
* 缺点:类加载时就初始化单例对象,浪费内存。(简单来说:不能延迟加载)
*/
public class HungrySingleton {
//定义唯一实例,private防止被其他对象修改
private static final HungrySingleton instance = new HungrySingleton();
//特点3:向其他对象提供单例获取方法
private static HungrySingleton getInstance() {
return instance;
}
//构造器私有化,防止其他地方创建对象
private HungrySingleton() {
}
}
1.1.2·懒汉式+双重检验
/**
* 单例模式:懒汉式->双检锁
* 在懒汉式的基础上加上双重检验锁,保证线程安全和延迟初始化
* 效果和静态内部类式一样
*/
public class LazySingleTon {
/*
volatile关键字的作用:
1.保证可见性:任意线程修改了值,立即对所有用到的线程有效,都会读取到新值
2.保证有序性:进制JVM在编译期间或运行期间对指令(代码)进行重排序优化
*/
private volatile static LazySingleTon instance = null; //定义唯一实例,private防止被其他对象修改
//特点3:向其他对象提供单例获取方法
public static LazySingleTon getInstance() {
if (instance == null) {
synchronized (LazySingleTon.class) {
if (instance == null) {
//noinspection InstantiationOfUtilityClass
instance = new LazySingleTon();
}
}
}
return instance;
}
//构造器私有化,防止其他地方创建对象
private LazySingleTon() {
}
}
1.1.3·静态内部类
/**
* 单例模式:懒汉式->静态内部类
* 使用静态内部类来实现懒汉式,保证线程安全和性能。
* 功能和懒汉式#双检锁式一样,两者等同
*/
public class InnerClsSingleton {
/*
Tips:
1.JVM在加载外部类的时候并不会加载其静态内部类,只有在使用到静态内部类的时候才会对静态内部类进行加载。
类的静态变量是在类加载的时候进行加载的,这样静态内部类实现单例模式就有一个特性:
如果没有使用到这个实例,这个实例就不会进行加载。这和懒汉模式一样,能有效节省资源。
2.JVM底层保证类加载的安全,即使在高并发的情况下,类的加载都只有一次,这就保证了创建单例时的并发安全性。
*/
private static class SingletonHolder {
@SuppressWarnings("InstantiationOfUtilityClass")
private static final InnerClsSingleton INSTANCE = new InnerClsSingleton();
}
//外部类加载的时候不会初始化内部类的
public static InnerClsSingleton getInstance(){
return SingletonHolder.INSTANCE;
}
//构造器私有化,防止其他地方创建对象
private InnerClsSingleton() {}
}
1.1.4·枚举
/**
* 单例模式:枚举
* 原理:
* 枚举中的各个枚举项是通过static来定义的,保证了线程安全问题,和饿汉式一样
* 优点:不能通过反射创建,这是其他单例模式不具备的特点
* 缺点:和饿汉式一样,不能延迟加载
*/
public enum EnumSingleton {
INSTANCE,ORC;
public String getTips() {
return "枚举单例";
}
}
1.2·原型模式
/**
* 原型设计模式:允许通过复制现有对象来创建新对象,而不是通过实例化类来创建新对象。
* 在需要创建大量相似对象时非常有用,它可以避免重复创建对象,从而提高性能,并且可以根据需要实现浅拷贝或深拷贝。
* 在Java中,原型模式的实现通常涉及到实现Cloneable接口和重写clone()方法。
*/
//此类为原型
public abstract class Shape implements Cloneable{
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public abstract void desciption();
@Override
public Shape clone() {
try {
return (Shape) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
//此类是Shape的实现类
public class CircleShape extends Shape {
public CircleShape() {
setType("Circle");
}
@Override
public void desciption() {
System.out.println("Circle Shape");
}
}
//此类是Shape的实现类
public class SquareShape extends Shape {
public SquareShape() {
setType("Square");
}
@Override
public void desciption() {
System.out.println("Square Shape");
}
}
//这是一个缓存类
public class ShapePrototypePattern {
//这里使用静态代码块设置初始类
static {
cache = new HashMap<>();//在这里创建对象,保证了下面调用的正确性
addShape("Circle", new CircleShape());
addShape("Square", new SquareShape());
}
private static final Map<String, Shape> cache;
//根据类型获取具体实现类
public static Shape getShape(String shapeType) {
Shape shape = cache.get(shapeType.toLowerCase(Locale.CHINA));
return shape.clone();
}
//添加新类型
public static void addShape(String shapeType, Shape shape) {
if (!cache.containsKey(shapeType.toLowerCase(Locale.CHINA))) {
cache.put(shapeType.toLowerCase(Locale.CHINA), shape);
}
}
}
//这是调用的Demo
public class Main {
// 使用getShape()方法来获取Shape对象的副本,并输出它们的类型。由于我们使用了原型模式,
// 所以我们可以通过复制现有对象来创建新对象,而无需实例化类。
public static void main(String[] args) {
ShapePrototypePattern.getShape("Circle").desciption();
ShapePrototypePattern.getShape("Square").desciption();
}
}