一、单例模式
单例模式是(Singleton Pattern)Java中最常用的设计模式之一,它保证一个类仅有一个实例,并提供一个全局访问点。
实现单例模式的核心是将类的构造方法私有化,以防止外部直接通过构造函数创建实例。同时,类内部需要提供一个静态方法或变量来获取该类的唯一实例。单例模式分为饿汉式单例(立即加载)和懒汉式单例(延迟加载)。
饿汉式单例:线程安全
public class Singleton1 {
/**
* 在类的内部可以访问私有结构,所以可以在类的内部产生实例化对象
*/
private static Singleton1 instance = new Singleton1();
/**
* private 声明构造
*/
private Singleton1() {
}
/**
* 返回对象实例
*/
public static Singleton1 getInstance() {
return instance;
}
}
懒汉式单例:
当多个线程并发执行 getInstance 方法时,懒汉式会存在线程安全问题,所以用到了 synchronized 来实现线程的同步,当一个线程获得锁的时候其他线程就只能在外等待其执行完毕。而饿汉式则不存在线程安全的问题。
public class Singleton2 {
/*线程不安全*/
// // 指向自己实例的私有静态引用
// private static Singleton2 singleton2;
//
// // 私有的构造方法
// private Singleton2(){}
//
// // 以自己实例为返回值的静态的公有方法,静态工厂方法
// public static Singleton2 getSingleton2(){
// // 被动创建,在真正需要使用时才去创建
// if (singleton2 == null) {
// singleton2 = new Singleton2();
// }
// return singleton2;
// }
/**
* 声明变量
*/
private static volatile Singleton2 singleton = null;
/**
* 私有构造方法
*/
private Singleton2() {
}
/**
* 提供对外方法
* @return
*/
public static Singleton2 getInstance() {
// 还未实例化
if (singleton == null) {
synchronized (Singleton2.class) {
if (singleton == null) {
singleton = new Singleton2();
}
}
}
return singleton;
}
}
JDK 中的应用:
- java.lang.Runtime.getRuntime()
- java.util.logging.Logger
Spring 中的应用:Spring 的 Bean 默认是单例模式。可以通过 @Scope("prototype") 将其改为多例。
二、工厂模式
根据需求,在用于不同的场景下,创建不同的对象。
public interface Sender {
void Send();
}
public class MailSender implements Sender{
@Override
public void Send() {
System.out.println("This is mail sender...");
}
}
public class SmsSender implements Sender{
@Override
public void Send() {
System.out.println("This is sms sender...");
}
}
public class FactoryPattern {
public static void main(String[] args) {
Sender sender = produce("mail");
sender.Send();
}
public static Sender produce(String str) {
if ("mail".equals(str)) {
return new MailSender();
} else if ("sms".equals(str)) {
return new SmsSender();
} else {
System.out.println("输入错误...");
return null;
}
}
}
在此基础上,若存在多个分支判断条件,很容易出现传递的字符串出错,则不能正确创建对象,因此可以多封装一个类,用来将分支判断替换为每个方法,降低耦合,这种模式是多个工厂方法模式,是提供多个工厂方法,分别创建对象。
public interface Sender {
void Send();
}
public class MailSender implements Sender{
@Override
public void Send() {
System.out.println("This is mail sender...");
}
}
public class SmsSender implements Sender{
@Override
public void Send() {
System.out.println("This is sms sender...");
}
}
public class SendFactory {
public Sender produceMail() {
return new MailSender();
}
public Sender produceSms() {
return new SmsSender();
}
}
public class FactoryPattern {
public static void main(String[] args) {
SendFactory factory = new SendFactory();
Sender sender = factory.produceMail();
sender.Send();
}
}
JDK 中的应用:
- java.util.Calendar.getInstance()
- javax.xml.parsers.DocumentBuilderFactory.newInstance()
Spring 中的应用:
- BeanFactory 和 ApplicationContext 都是工厂模式的体现。
三、建造者模式
建造者模式用于创建复杂对象,就是将复杂对象的创建过程拆分成多个简单对象的创建过程,并将这些简单对象组合起来构建出复杂对象。
角色组成:
- 产品类(Product):表示被创建的复杂对象。它通常包含多个部分或者组成,并由具体的建造者逐步构建而成。 Meal
- 抽象建造者类(Builder):定义了建造复杂对象所需要的各个部分的创建方法。它通常包括多个构建方法和一个返回产品的方法。 MealBuilder
- 具体建造者类(ConcreteBuilder):实现Builder接口,并提供各个部分或者组成的构建方法。 BeefBurgerMealBuilder、ChickenMealBuilder、ShrimpMealBuilder
- 指挥者类(Director):负责控制建造者的构建顺序,指挥建造者如何构建复杂对象。MealDirector
/**
* @Author: EstellaQ
* @Date: 2025/4/17 15:43
* @Description: 产品类
**/
@Data
public class Meal {
//汉堡包
private String burger;
//薯条
private String fries;
//饮料
private String drink;
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 15:44
* @Description: 建造者接口
**/
public interface MealBuilder {
Meal meal=new Meal();
//构建汉堡
public void buildBurger();
//构建薯条
public void buildFries();
//构建饮料
public void buildDrink();
public default Meal getMeal(){
return meal;
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 15:46
* @Description: 牛肉套餐建造者
**/
public class BeefBurgerMealBuilder implements MealBuilder{
@Override
public void buildBurger() {
meal.setBurger("牛肉汉堡");
}
@Override
public void buildFries() {
meal.setFries("大份薯条");
}
@Override
public void buildDrink() {
meal.setDrink("中杯可乐");
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 15:46
* @Description: 鸡肉套餐建造者
**/
public class ChickenMealBuilder implements MealBuilder{
@Override
public void buildBurger() {
meal.setBurger("鸡肉汉堡");
}
@Override
public void buildFries() {
meal.setFries("中份薯条");
}
@Override
public void buildDrink() {
meal.setDrink("大杯果汁");
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 15:46
* @Description: 虾肉套餐建造者
**/
public class ShrimpMealBuilder implements MealBuilder{
@Override
public void buildBurger() {
meal.setBurger("虾肉汉堡");
}
@Override
public void buildFries() {
meal.setFries("小份薯条");
}
@Override
public void buildDrink() {
meal.setDrink("大杯芬达");
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 15:50
* @Description: 指挥者
**/
public class MealDirector {
private MealBuilder mealBuilder;
public void setMealBuilder(MealBuilder mealBuilder){
this.mealBuilder=mealBuilder;
}
public Meal getMeal(){
return mealBuilder.getMeal();
}
//制作套餐
public void constructMeal(){
mealBuilder.buildBurger();
mealBuilder.buildFries();
mealBuilder.buildDrink();
}
}
public class BuilderPattern {
public static void main(String[] args) {
//创建指导者
MealDirector director=new MealDirector();
//执导建造牛肉套餐
director.setMealBuilder(new BeefBurgerMealBuilder());
director.constructMeal();
Meal meal = director.getMeal();
System.out.println("牛肉套餐:"+meal.toString());
//鸡肉套餐
director.setMealBuilder(new ChickenMealBuilder());
director.constructMeal();
Meal meal2 = director.getMeal();
System.out.println("鸡肉套餐:"+meal2.toString());
//虾肉套餐
director.setMealBuilder(new ShrimpMealBuilder());
director.constructMeal();
Meal meal3 = director.getMeal();
System.out.println("虾肉套餐:"+meal3.toString());
}
}
JDK 中的应用:
- StringBuilder
- Stream.Builder
Spring 中的应用:
- UriComponentsBuilder 用于构建 URI。
四、 适配器模式
它允许将不兼容的对象转换成可兼容的接口。主要目的是解决在不改变现有代码的情况下,使不兼容的接口之间能够正常工作,通过创建一个中间转换的适配器来将一个对象转换成我们所需要的接口。
角色组成
- 目标接口(target):需要适配的标准接口。
- 源对象(source):需要被适配的不兼容对象。
- 适配器对象(adapter):充当中间转换角色,该对象将源对象转换成目标接口。
/**
* @Author: EstellaQ
* @Date: 2025/4/17 16:20
* @Description: 目标接口
**/
public interface Target {
/**
* 翻译
* @param source 母语
* @param target 要翻译成的语种
* @param words 内容
*/
void translate(String source,String target,String words);
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 16:20
* @Description: 源对象
**/
public class Translator {
//英——》汉
public void translateInZh(String words){
if("hello world!".equals(words)){
System.out.println("翻译成中文:”你好世界!“");
}
}
//汉——》英
public void translateInEn(String words){
if("你好世界!".equals(words)){
System.out.println("Translate in English:”hello world!“");
}
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 16:21
* @Description: 类适配器:通过多重继承目标接口和被适配者类方式来实现适配
**/
public class ClassAdapter extends Translator implements Target{
@Override
public void translate(String source, String target, String words) {
if("中文".equals(source) && "英文".equals(target)) {
//汉--》英
this.translateInEn(words);
} else {
//英--》汉
this.translateInZh(words);
}
}
}
public class AdapterPattern {
public static void main(String[] args) {
//创建一个类适配器对象
ClassAdapter adapter=new ClassAdapter();
adapter.translate("中文", "英文", "你好世界!");
adapter.translate("英语","中文","hello world!");
}
}
五、 装饰器模式
装饰器模式在不改变原始类的基础上,动态累积扩展其功能。原始对象和装饰类对象都要实现原始对象的接口。
/**
* @Author: EstellaQ
* @Date: 2025/4/17 16:55
* @Description: 原始对象的接口
**/
public interface ICoffee {
void makeCoffee();
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 16:56
* @Description: 原始对象
**/
public class OriginalCoffee implements ICoffee{
@Override
public void makeCoffee() {
System.out.print("原味咖啡 ");
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 16:56
* @Description: 装饰器基类
**/
public abstract class CoffeeDecorator implements ICoffee{
private ICoffee coffee;
public CoffeeDecorator(ICoffee coffee){
this.coffee=coffee;
}
@Override
public void makeCoffee() {
coffee.makeCoffee();
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 16:58
* @Description: 加奶的装饰
**/
public class MilkDecorator extends CoffeeDecorator{
public MilkDecorator(ICoffee coffee) {
super(coffee);
}
@Override
public void makeCoffee() {
super.makeCoffee();
addMilk();
}
private void addMilk(){
System.out.print("加奶 ");
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 16:58
* @Description: 加糖的装饰
**/
public class SugarDecorator extends CoffeeDecorator{
public SugarDecorator(ICoffee coffee) {
super(coffee);
}
@Override
public void makeCoffee() {
super.makeCoffee();
addSugar();
}
private void addSugar(){
System.out.print("加糖 ");
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 17:00
* @Description: 装饰器模式测试
**/
public class DecoratorPattern {
public static void main(String[] args) {
//原味咖啡
ICoffee coffee=new OriginalCoffee();
coffee.makeCoffee();
System.out.println("");
//加奶的咖啡
coffee=new MilkDecorator(coffee);
coffee.makeCoffee();
System.out.println("");
//先加奶后加糖的咖啡
coffee=new SugarDecorator(coffee);
coffee.makeCoffee();
}
}
JDK 中的应用:
- java.io.BufferedInputStream 和 java.io.BufferedOutputStream
Spring 中的应用:
- BeanPostProcessor 用于动态修改 Bean 的行为。
六、 代理模式
代理模式的结构比较简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问,下面来分析其基本结构。
角色组成:
- 抽象主题(Subject)类(业务接口类):通过接口或抽象类声明真实主题和代理对象实现的业务方法,服务端需要实现该方法。
- 真实主题(Real Subject)类(业务实现类):实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
- 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
静态代理
静态代理服务于单个接口,我们来考虑实际工程中的一个例子,现在已经有业务代码实现一个增删功能,原有的业务代码由于仍有大量程序无法改变,现在新增需求,即以后每执行一个方法输出一个日志。
/**
* @Author: EstellaQ
* @Date: 2025/4/17 17:38
* @Description: 业务接口
**/
public interface DateService {
void add();
void del();
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 17:39
* @Description: 委托类
**/
public class DateServiceImplA implements DateService{
@Override
public void add() {
System.out.println("成功添加!");
}
@Override
public void del() {
System.out.println("成功删除!");
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 17:40
* @Description: 代理类
**/
public class DateServiceProxy implements DateService{
DateServiceImplA server = new DateServiceImplA();
@Override
public void add() {
server.add();
System.out.println("程序执行add方法,记录日志.");
}
@Override
public void del() {
server.del();
System.out.println("程序执行del方法,记录日志.");
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 17:39
* @Description: 代理模式测试
**/
public class ProxyPattern {
public static void main(String[] args) {
DateService service = new DateServiceProxy();
service.add();
service.del();
}
}
动态代理
动态代理可以帮助我们仅仅在需要的时候再创建代理类,减少资源浪费,此外由于动态代理是一个模板的形式,也可以减少程序的代码量,例如在静态代码示例中,我们在每个方法中加入System.out.println("程序执行***方法,记录日志.");,当业务方法非常多时,我们也得为每个业务方法加上记录日志的语句,而动态代理中将方法统一管理,无论几个业务方法都只需要一条记录语句即可实现,具体请看代码。
/**
* @Author: EstellaQ
* @Date: 2025/4/17 17:48
* @Description: 动态代理的代理类
**/
public class ProxyInvocationHandler implements InvocationHandler {
private DateService service;
public ProxyInvocationHandler(DateService service) {
this.service = service;
}
public Object getDateServiceProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), service.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
var result = method.invoke(service, args); // 让service调用方法,方法返回值
System.out.println(proxy.getClass().getName() + "代理类执行" + method.getName() + "方法,返回" + result + ",记录日志!");
return result;
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 17:39
* @Description: 代理模式测试
**/
public class ProxyPattern {
public static void main(String[] args) {
//静态代理
// DateService service = new DateServiceProxy();
// service.add();
// service.del();
//动态代理
DateService serviceA = new DateServiceImplA();
DateService serviceProxy = (DateService) new ProxyInvocationHandler(serviceA).getDateServiceProxy();
serviceProxy.add();
serviceProxy.del();
}
}
七、 策略模式
该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。 我认为跟工厂模式的思想很相似
角色组成:
抽象策略(Strategy)类
具体策略(Concrete Strategy)类
环境(Context)类
/**
* @Author: EstellaQ
* @Date: 2025/4/17 18:04
* @Description: 抽象算法的策略类,定义所有支持的算法的公共接口
**/
public interface Strategy {
/**
* 算法方法
*/
public void AlgorithmInterface();
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 18:04
* @Description: 策略实现类A
**/
public class ConcreteStrategyA implements Strategy{
@Override
public void AlgorithmInterface() {
System.out.println("算法A的实现");
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 18:04
* @Description: 策略实现类B
**/
public class ConcreteStrategyB implements Strategy{
@Override
public void AlgorithmInterface() {
System.out.println("算法B的实现");
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 18:04
* @Description: 策略实现类C
**/
public class ConcreteStrategyC implements Strategy{
@Override
public void AlgorithmInterface() {
System.out.println("算法C的实现");
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 18:06
* @Description: 上下文,维护一个对策略类对象的引用
**/
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void contextInterface(){
strategy.AlgorithmInterface();
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 18:03
* @Description: 策略模式的测试类
**/
public class StrategyPattern {
public static void main(String[] args) {
Context context;
context = new Context(new ConcreteStrategyA());
context.contextInterface();
context = new Context(new ConcreteStrategyB());
context.contextInterface();
context = new Context(new ConcreteStrategyC());
context.contextInterface();
}
}
JDK 中的应用:
- java.util.Comparator 是典型的策略模式。
Spring 中的应用:
- 事务管理(TransactionManager),支持编程式和声明式事务。
八、 观察者模式
观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。
角色组成:
- 主题(Subject):也称为被观察者或可观察者,它是具有状态的对象,并维护着一个观察者列表。主题提供了添加、删除和通知观察者的方法。
- 观察者(Observer):观察者是接收主题通知的对象。观察者需要实现一个更新方法,当收到主题的通知时,调用该方法进行更新操作。
- 具体主题(Concrete Subject):具体主题是主题的具体实现类。它维护着观察者列表,并在状态发生改变时通知观察者。
- 具体观察者(Concrete Observer):具体观察者是观察者的具体实现类。它实现了更新方法,定义了在收到主题通知时需要执行的具体操作。
/**
* @Author: EstellaQ
* @Date: 2025/4/17 18:42
* @Description: 主题类,被观察者
**/
public class Subject {
private List<Observer> observers = new ArrayList<Observer>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyAllObservers();
}
public void attach(Observer observer){
observers.add(observer);
}
public void notifyAllObservers(){
for (Observer observer : observers) {
observer.update();
}
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 18:43
* @Description: 被通知者的抽象类
**/
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 18:46
* @Description: 被通知者的实现类
**/
public class BinaryObserver extends Observer{
public BinaryObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Binary String: "
+ Integer.toBinaryString( subject.getState() ) );
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 18:46
* @Description: 被通知者的实现类
**/
public class OctalObserver extends Observer{
public OctalObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Octal String: "
+ Integer.toOctalString( subject.getState() ) );
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 18:46
* @Description: 被通知者的实现类
**/
public class HexaObserver extends Observer{
public HexaObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Hex String: "
+ Integer.toHexString( subject.getState() ) );
}
}
/**
* @Author: EstellaQ
* @Date: 2025/4/17 18:48
* @Description: 观察者模式测试
**/
public class ObserverPattern {
public static void main(String[] args) {
Subject subject = new Subject();
new HexaObserver(subject);
new OctalObserver(subject);
new BinaryObserver(subject);
System.out.println("First state change: 15");
subject.setState(15);
System.out.println("Second state change: 10");
subject.setState(10);
}
}
JDK 中的应用:
- java.util.Observer 和 java.util.Observable
- javax.swing.event.ChangeListener
Spring 中的应用:
- ApplicationEvent 和 ApplicationListener 是典型实现。