设计模式的使用场景

什么是设计模式

设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

  • 目的

    • 提高代码的可重用性,避免重复开发类似的解决方案。
    • 增强代码的可维护性和可读性,使得其他人更容易理解和扩展代码。
    • 促进软件的架构设计更加合理和灵活。

    上面的描述比较笼统,简单的说设计模式就是一种遵循 ETC (Eaiser To Change)原则的设计理念,目的是为了让我们在进行业务扩展或者功能扩展的同时对之前的代码造成更少的影响,同时减少出错成本和测试成本。

设计模式分类

  • 创建型设计模式

    • 单例模式 (Spring Bean)
    • 工厂模式 (BeanFactory、SqlSessionFactory)
  • 结构型模式

    • 适配器模式 (转接器)
    • 桥接模式
  • 行为型模式

    • 策略模式
    • 观察者模式
    • 命令模式

单例设计模式

单例设计模式的设计思想主要是减少频繁创建对象导致的 内存 & CPU 消耗。

  • 例如:Spring 的 Bean 对象大多数就是一个单例对象 | 工具类

注意事项: 单例对象在传统的规约下只能初始化一次,并且需要声明用 public static final 进行声明

第一种单例模式: 静态内部类

java 复制代码
public final class SingleOne {

    public static class INSTANCE {
        public static final SingleOne instance = new SingleOne();
    }

    public static volatile SingleOne instance;
}

第二种单例模式: volatile + 双重判空检测 (volatile 保证对象可见性 + 双重判空检测 降低锁粒度)

java 复制代码
public final class SingleOne {

    /**
     * 全局锁监视器
     */
    public static final Object MONITOR = new Object();

    /**
     * 获取
     *
     * @return
     */
    public static SingleOne getInstance() {

        if (null == instance) {
            synchronized (MONITOR) {
                if (null == instance) {
                    instance = new SingleOne();
                }
            }
        }

        return instance;
    }
}

第三种单例模式: 枚举类

java 复制代码
public enum SingleTwo {

    ONE,


    TWO,


    THREE
}

1、打开 Terminal 切换到枚举类所在的目录 使用 javac 编译一下对应的枚举类 javac SingleTwo.java 2、使用 javap 查看一下对应的 class 文件

java 复制代码
public final class com.ayi.singlen.SingleTwo extends java.lang.Enum<com.ayi.singlen.SingleTwo> {
  public static final com.ayi.singlen.SingleTwo ONE;
  public static final com.ayi.singlen.SingleTwo TWO;
  public static final com.ayi.singlen.SingleTwo THREE;
  public static com.ayi.singlen.SingleTwo[] values();
  public static com.ayi.singlen.SingleTwo valueOf(java.lang.String);
  static {};
}

通过观察我们会发现每一个我们声明的枚举属性都被解析成了一个 SingleTwo 的对象 属性名就是我们声明的枚举名,并且使用 public static final 进行了声明。

工厂设计模式

在工厂设计模式中,定义一个创建对象的工厂类,它根据不同的条件或参数来创建不同的具体产品对象。这样做的好处是将对象的创建与使用进行分离,客户端不需要直接了解具体产品类的细节,只需要与工厂进行交互来获取所需的对象。

示例: 生产实体

csharp 复制代码
public interface CarModel {

    /**
     * 接口定义 action
     */
    void product();

}
csharp 复制代码
public class BenzCar implements CarModel {


    public void product() {
        System.out.println("生产奔驰车");
    }
}
csharp 复制代码
public class BmwCar implements CarModel {

    public void product() {
        System.out.println("生产宝马车");
    }
}

工厂类: 提供生产能力

arduino 复制代码
public interface Factory {
       
    // 提供通用汽车生产能力 action 
    CarModel getInstance(String mark);
}
java 复制代码
public final class CarFactory implements Factory {
    
    // 保证线程安全
    public static final ConcurrentHashMap<String, CarModel> cacheCarMap =
            new ConcurrentHashMap<>(8);
    
    // 声明私有构造器防止汽车对象 factory 被初始化
    private  CarFactory() {
        
    }

    public static CarModel getInstance(String mark) {

        CarEnums carEnums = CarEnums.getCarKind(mark);

        CarModel carModel = null;

        String cardName = carEnums.name();

        if (cacheCarMap.contains(cardName)) {
            return cacheCarMap.get(cardName);
        }

        switch (cardName) {
            case "BMW":

                carModel = new BmwCar();
                cacheCarMap.putIfAbsent(cardName, carModel);

                break;

            case "BENZ":
                carModel = new BenzCar();
                cacheCarMap.putIfAbsent(cardName, carModel);
                break;

            default:
                break;
        }

        return carModel;
    }
}

适配器模式

通过上图我们可以发现这是一个 type-c 转安卓的转接器,目的是为了解决 我们的充电设备只有安卓接口的情况下 + 我们只有 type-c 充电器的痛点。

代码示例:

java 复制代码
// 安卓手机接口
public interface AndroidInterface {
    // typeC接口耳机
    void androidHeadSet();
    // ..... 其他接口
}

// 安卓手机实现类
public class AndroidHeadSet implements AndroidInterface {
    @Override
    public void androidHeadSet() {
        System.out.println("这里是使用安卓耳机接口的连接");
    }
}

// iphone苹果手机接口
public interface IPhoneInterface {
    // lightning接口耳机
    void iphoneHeadSet();
}
// 苹果手机实现类
public class IPhoneHeadSet implements IPhoneInterface{
    @Override
    public void iphoneHeadSet() {
        System.out.println("这里是使用lightning接口耳机的连接");
    }
}

// 注意接下来!!!
// 适配器类 + 组合模式为 class 提供格外的能力
public class ObjectHeadSetAdapter implements IPhoneInterface {

    private AndroidInterface androidInterface;

    public ObjectHeadSetAdapter(AndroidInterface androidInterface) {
        this.androidInterface = androidInterface;
    }

    @Override
    public void iphoneHeadSet() {
        androidInterface.androidHeadSet();
    }
}

public class Client {
    public static void main(String[] args) {
        // 直接通过苹果接口 使用苹果耳机
        IPhoneInterface iPhoneInterface = new IPhoneHeadSet();
        iPhoneInterface.iphoneHeadSet();
        //通过类的适配器进行连接
        HeadSetAdapter headSetAdapter = new HeadSetAdapter();
        headSetAdapter.iphoneHeadSet();
        //通过对象的适配器进行连接
        AndroidInterface androidInterface = new AndroidHeadSet();
        ObjectHeadSetAdapter objectHeadSetAdapter = new ObjectHeadSetAdapter(androidInterface);
        objectHeadSetAdapter.iphoneHeadSet();
    }
}

策略模式

它定义了一系列算法(策略),将每个算法封装起来,使它们可以相互替换。策略模式使得算法的变化独立于使用算法的客户代码。(简单来说就是对同一种行为 action 的不同执行方式)

定义行为

csharp 复制代码
public interface SendSms {

    void sendMessage();

}
typescript 复制代码
public class AliSendSms implements SendSms{

    @Override
    public void sendMessage() {
        System.out.println("阿里短信");
    }
}
typescript 复制代码
public class TencentSendSms implements SendSms{

    @Override
    public void sendMessage() {
        System.out.println("使用腾讯发送短信");
    }
}
csharp 复制代码
public final class SendSmsStrategyContainer {

    public static final ConcurrentHashMap<String, SendSms> strategyMap
            = new ConcurrentHashMap<>(8);

    static  {
        strategyMap.putIfAbsent("ali", new AliSendSms());
        strategyMap.putIfAbsent("tencent", new TencentSendSms());
    }

    private SendSmsStrategyContainer() {}

    public void execute(String mark) {

        if ("ali".equals(mark)) {
            strategyMap.get("ali").sendMessage();
        } else if ("tencent".equals(mark)) {
            strategyMap.get("tencent").sendMessage();
        }
    }
}

封装通用策略模板

定义抽象策略类

csharp 复制代码
public interface AbstractExecuteStrategy<REQUEST, RESPONSE> {


    default String mark() {
        return null;
    }

    /**
     * 执行没有返回值
     *
     * @param requestParam
     */
    default void execute(REQUEST requestParam) {

    }

    /**
     * 执行携带返回值
     *
     * @param request
     */
    default void executeResp(REQUEST request) {

    }

    /**
     * 异常处理
     */
    default void exceptionProcess() {

    }

    /**
     * 后置处理
     */
    default void afterCommit() {

    }
}

定义策略选择执行器

kotlin 复制代码
public class AbstractStrategyChoose {

    // 策略对象 Map



    // choose


    // chooseAndExecute


    // chooseAndExecuteResp


    // 策略收集

}

观察者模式

在观察者模式中,存在被观察的对象(主题)和观察该对象的多个观察者。主题负责在自身状态发生变化时通知所有的观察者,而观察者则根据主题的通知进行相应的操作或更新自身的状态。

代码案例

arduino 复制代码
// 观察者接口
interface Observer {
    void update(String message);
}
typescript 复制代码
// 具体观察者
class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " 收到消息: " + message);
    }
}
typescript 复制代码
// 主题
class Subject {
    private List<Observer> observers = new ArrayList<>();

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

命令模式

命令模式,它其实是一种设计模式,主要用来把一个请求或者操作封装成一个对象。这样做的好处是什么呢?主要是让你的软件设计更加灵活,更容易扩展和维护。

基于 Apache-Commons-Chain 实现

代码案例

java 复制代码
public class LoginPasswordValidateCommand implements BaseCommand {

    @Override
    public boolean execute(Context context) throws Exception {

        String password = (String) context.get("password");

        if (null == password && "" == password) {
            throw new RuntimeException("密码不能为空");
        }

        // 验证通过,继续执行链中的下一个命令
        return Command.CONTINUE_PROCESSING;
    }

    @Override
    public int order() {
        return 0;
    }
}
java 复制代码
public class LoginUserNameValidateCommand implements BaseCommand {


    @Override
    public boolean execute(Context context) throws Exception {

        String username = (String) context.get("username");
        System.out.println("1231231");
        if (null == username || "" == username) {
            System.out.println("用户名不能为空!");
            throw new RuntimeException("用户名不能为空!");
        }

        // 验证通过,继续执行链中的下一个命令
        return Command.CONTINUE_PROCESSING;
    }

    @Override
    public int order() {
        return 2;
    }
}
scala 复制代码
public class LoginChain extends ChainBase {

    private PriorityQueue<Command> priorityQueue = new PriorityQueue<>();

    // 这里可以考虑使用 Spring 提供的 InitializingBean  接口来进行命令初始化
    public LoginChain() {
        super();
        // 将命令添加到链中
        addCommand(new LoginPasswordValidateCommand());
        addCommand(new LoginUserNameValidateCommand());
    }

    @Override
    public void addCommand(Command command) {

        priorityQueue.add(command);
        commands = (Command[]) priorityQueue.toArray();
    }


    // 实现 InitializingBean 进行初始化
}

为了实现 命令的 顺序执行我们可以自定义一个 OrderCommond 实现顺序功能,在进行命令组装时 去重写 ChainBase 来进行扩展。可以结合一下 Spring 生命周期函数 InitializingBean

相关推荐
handsomethefirst1 小时前
【设计模式】【行为型模式】【责任链模式】
设计模式·责任链模式
白色的生活2 小时前
设计模式学习-《策略模式》
学习·设计模式·策略模式
Eric⠀2 小时前
【02问:前端常见的设计模式】
前端·javascript·vue.js·设计模式·js
java6666688882 小时前
工厂设计模式的实现与应用场景分析
设计模式
xintaiideas2 小时前
熟练掌握 Java 设计模式,如工厂、代理、策略、责任链等设计模式,并善⽤设计原则构建可复⽤代码
java·开发语言·设计模式
繁星十年3 小时前
在C++中,工厂模式的思考(《C++20设计模式》及常规设计模式对比)
c++·设计模式·c++20
且随疾风前行.3 小时前
技术成神之路:设计模式(二)建造者模式
java·设计模式·建造者模式
确定吗阿斌3 小时前
简述设计模式-代理模式
设计模式·代理模式
臻一12 小时前
C++编程(五)单例模式 友元
开发语言·c++·设计模式
小白要code13 小时前
设计模式-抽象工厂模式
java·设计模式·抽象工厂模式