手撕四种常用设计模式(工厂,计谋,代理,单例)

立山  论坛元老 | 2025-5-20 22:53:19 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 2062|帖子 2062|积分 6186

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
工厂模式

一、工厂模式的总体长处


  • 解耦:客户端与具体实现类解耦,符合“开闭原则”。
  • 统一创建:对象创建交由工厂处置惩罚,便于会合控制。
  • 增强可维护性:新增对象种类时不需要大改动调用代码。
  • 便于扩展:易于管理产品族或产品等级结构。、


手写静态工厂模式,通过一个汽车静态工厂负责创建汽车

特点:



  • 工厂类通过一个静态方法来返回差异的对象。
  • 客户端通过传入参数决定创建哪个类。
✅ 长处:



  • 实现简朴,结构清晰。
  • 对客户端隐藏了对象的具体创建过程。
⚠️ 缺点:



  • 不符合开闭原则(新增产品需修改 createCar() 方法)。
  • 工厂职责过重,产品一多代码臃肿。
  1. public class StaticFactoryModel {
  2.    
  3.     public static void main(String[] args){
  4.         car car=new CarFactory.createCar("Tesla");
  5. }
  6. interface car{
  7.     void drive();
  8. }
  9. class Tesla implements car{
  10.     @Override
  11.     public void drive(){
  12.         System.out.println("drive Tesla");
  13.     }
  14. }
  15. class toyota implements car{
  16.     @Override
  17.     public void drive(){
  18.         System.out.println("drive toyota");
  19.     }
  20. }
  21. class CarFactory{
  22.     public static car createCar(String type){
  23.         switch(type){
  24.             case"Tesla": return new Tesla();
  25.             case"toyota":return new toyota();
  26.             default:throw new IllegalArgumentException("UnKnow Car");
  27.         }
  28.     }
  29. }
复制代码
手写工厂方法模式

特点:



  • 将创建对象的工作延迟到子类,通过差异工厂子类创建差异对象。
✅ 长处:



  • 满意开闭原则,新增产品只需新增对应工厂。
  • 结构清晰,职责单一,每个工厂只负责一种产品的创建。
⚠️ 缺点:



  • 类的数目变多,增长体系复杂度。
  • 只能生产单一类型的产品。
  1. package com;
  2. public class FactoryMethod {
  3.     public static void main(String[] args) {
  4.         phoneFactory factory=new iPhoneFactory();
  5.         phone myphone=factory.createPhone();
  6.         myphone.call();
  7.     }
  8. }
  9. interface phone{
  10.     public void call();
  11. }
  12. class iPhone implements phone{
  13.     @Override
  14.     public void call(){
  15.         System.out.println("iPhone call");
  16.     }
  17. }
  18. class Huawei implements phone{
  19.     @Override
  20.     public void call(){
  21.         System.out.println("Huawei call");
  22.     }
  23. }
  24. interface phoneFactory{
  25.     public phone createPhone();
  26. }
  27. class iPhoneFactory implements phoneFactory{
  28.     @Override
  29.     public phone createPhone(){
  30.         return new iPhone();
  31.     }
  32. }
  33. class HuaweiFactory implements phoneFactory{
  34.     @Override
  35.     public phone createPhone(){
  36.         return new Huawei();
  37.     }
  38. }
复制代码
手写抽象工厂模式

✅ 特点:



  • 一个工厂可以生产多个相干的产品(如电脑 + 操作体系)。
✅ 长处:



  • 更强的扩展本事,可以生产“产品族”(多个相干产品)。
  • 高度封装了产品的创建细节,对客户端透明。
⚠️ 缺点:



  • 不易新增“新产品”(好比新加一个 Printer 接口)需修改所有工厂。
  • 抽象程度更高,明白成本稍大。
  1. package com;
  2. public class AbstractFactory {
  3.     public static void main(String[] args){
  4.         ShowFactory factory=new WinFactory();
  5.         Computee myCom=factory.createCom();
  6.         Os myOs=factory.createOs();
  7.     }
  8. }
  9. interface Computee{
  10.     public void use();
  11. }
  12. interface Os{
  13.     public void call();
  14. }
  15. class hp implements  Computee{
  16.     @Override
  17.     public void use() {
  18.         System.out.println("useing window");
  19.     }
  20. }
  21. class AppleCom implements  Computee{
  22.     @Override
  23.     public void use() {
  24.         System.out.println("using apple");
  25.     }
  26. }
  27. class window implements Os{
  28.     @Override
  29.     public void call() {
  30.         System.out.println("calling window");
  31.     }
  32. }
  33. class AppleOS implements Os{
  34.     @Override
  35.     public void call() {
  36.         System.out.println("calling apple");
  37.     }
  38. }
  39. interface ShowFactory{
  40.     Computee createCom();
  41.     Os createOs();
  42. }
  43. class WinFactory implements ShowFactory{
  44.     @Override
  45.     public Computee createCom() {
  46.         return new hp();
  47.     }
  48.     @Override
  49.     public Os createOs() {
  50.         return new window();
  51.     }
  52. }
  53. //..另外一个工厂对应行为
复制代码
计谋模式

计谋模式
上下文负责生成具体的计谋类而且负责与客户端交互
抽象计谋类为抽象脚色,通常由一个接口大概抽象类实现,给出所有的具体计谋类需要的接口
具体计谋类:是实现接口,提供具体算法大概举动

计谋模式长处:


  • 算法解耦:将举动或算法封装在独立计谋类中,便于切换和扩展。
  • 避免多重判断:通过多态替代 if-else 或 switch,结构更清晰。
  • 符合开闭原则:新增计谋时无需改动已有代码,只需增长新计谋类。
  • 可复用性高:差异上下文可复用同一个计谋类,提拔代码复用率
  1. package com;
  2. public class Strategy {
  3. }
  4. interface paymentStragegy{
  5.     public void pay();
  6. }
  7. class wxpayMentStragegy implements paymentStragegy{
  8.     @Override
  9.     public void pay() {
  10.         System.out.println("useing wxpay");
  11.     }
  12. }
  13. class ApaymentStragegy implements paymentStragegy{
  14.     @Override
  15.     public void pay() {
  16.         System.out.println("using apay");
  17.     }
  18. }
  19. class context{
  20.     String type=System.getenv("stragegy");
  21.     public paymentStragegy mypayMent=null;
  22.     public context(){
  23.         switch(type){
  24.             case "1":mypayMent=new ApaymentStragegy();
  25.             case "2":mypayMent=new wxpayMentStragegy();
  26.             default:mypayMent=new wxpayMentStragegy();
  27.         }
  28.     }
  29. }
复制代码
代理模式

代理模式(Proxy Pattern)是结构型设计模式的一种,
定义如下:
为其他对象提供一种代理以控制对这个对象的访问。

这里使用jdk代理实当代理模式
长处:


  • 增强功能:在不修改原始对象的情况下增长额外逻辑(如权限校验、日记、事务等)。
  • 解耦结构:将业务逻辑与通用功能分离,代码更清晰、职责更单一。
  • 机动控制:可以在调用前后做一些处置惩罚,好比安全控制、延迟加载、访问控制等。
  • 支持动态扩展:通过 JDK 动态代理可根据接口生成代理对象,运行时更机动。
  1. package com;
  2. import java.awt.*;
  3. import java.lang.reflect.InvocationHandler;
  4. import java.lang.reflect.Method;
  5. import java.lang.reflect.Proxy;
  6. import java.lang.reflect.UndeclaredThrowableException;
  7. public class ProxyModel {
  8. }
  9. interface UserDao{
  10.     public void add();
  11.     public void delete();
  12. }
  13. class UserDaoImpl implements UserDao{
  14.     @Override
  15.     public void add() {
  16.         System.out.println("adding");
  17.     }
  18.     @Override
  19.     public void delete() {
  20.         System.out.println("deleteling");
  21.     }
  22. }
  23. class UserProxy implements InvocationHandler{
  24.     Object object;
  25.     public UserProxy(Object obb){
  26.         object=obb;
  27.     }
  28.     public Object getProxy(){
  29.         return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
  30.     }
  31.     @Override
  32.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  33.         System.out.println("代理加强前");
  34.         Object invoke = method.invoke(object, args);
  35.         System.out.println("代理加强后");
  36.         return invoke;
  37.     }
  38. }
复制代码

单例模式

定义:

单例模式就是一个类只有一个实例,而且还提供这个实例的全局访问点(避免一个全局使用的类频仍创建和烧毁,耗费体系资源)
设计要素



  • 一个私有的构造函数(确保只能由单例类自己创建实例)
  • 一个私有的静态变量(确保只有一个实例)
  • 一个公有的静态函数(给调用者提供调用方法)
单例类的构造方法不让其他人修改和使用;而且单例类自己只创建一个实例,这个实例,其他人也无法修改和直接使用;然后单例类提供一个调用方法,想用这个实例,只能调用。这样就确保了全局只创建了一次实例。
六种实现方式

懒汉式(线程不安全)

先不创建实例,当第一次被调用的时间再创建实例,延迟了实例化,不需要使用该类就不会实例化,节省了体系资源

线程不安全,如果多个线程同时进入了lazyd==null,此时如果还没有实例化,多个线程就会进行实例化,导致实例化了多个实例
  1. package com;
  2. public class LazyD {
  3.     private static LazyD lazyd;
  4.     private LazyD(){
  5.         
  6.     }
  7.     public static LazyD getUniqueInstance(){
  8.         if(lazyd==null){
  9.             lazyd=new LazyD();
  10.         }
  11.         return lazyd;
  12.     }
  13. }
复制代码
饿汉式不管使用还是不使用这个实例,直接实例化好实例即可,然后如果需要使用的时间,直接调用方法即可

长处:提前实例化了,避免了线程不安全的问题
缺点:直接实例花了这个实例,不会再延迟实例化,如果体系没有使用这个实例,就会导致操作体系的资源浪费
  1. package com;
  2. public class HungryD {
  3.     private static HungryD uniqueInstance=new HungryD();
  4.    
  5.     private HungryD(){};
  6.    
  7.     public static HungryD getUniqueInstance(){
  8.         return uniqueInstance;
  9.     }
  10. }
复制代码
懒汉式(线程安全)

和基本的懒汉式的区别就是在get方法上 加了一把 锁。如此一来,多个线程访问,每次只有拿到锁的的线程可以或许进入该方法,避免了多线程不安全问题的出现。
  1. package com;
  2. public class Singletion {
  3.    
  4.     private static Singletion uniqueInstance;
  5.    
  6.     private Singletion(){};
  7.    
  8.     public static synchronized Singletion getUniqueInstance(){
  9.         if(uniqueInstance==null){
  10.             uniqueInstance=new Singletion();
  11.         }
  12.         return uniqueInstance;
  13.     }
  14. }
复制代码
双重校验锁实现(线程安全)

双重查抄锁定(Double-Check Locking)是一种对线程安全的懒汉式单例模式的优化。传统的线程安全懒汉式存在性能问题——即使单例已经创建,每次调用仍旧需要获取锁,导致性能下降。
而双重查抄锁定通过在加锁前先判断实例是否已存在,避免了不必要的锁开销:


  • 如果实例已创建,直接返回实例,不进入加锁代码块,提拔了服从。
  • 如果实例未创建,多个线程同时进入时,由于加锁机制,只有一个线程可以或许进入锁内创建实例,保证线程安全。
因此,只有在首次实例化时会发生线程壅闭,之后的调用都不会再产生锁竞争,从而实现了高效且安全的延迟初始化。
焦点就是对比懒汉式的线程安全版本有性能提拔
还有就是使用volatile关键字修饰uniqueInstance实例变量的缘故原由如下
实验 uniqueInstance = new Singleton(); 时,实际上分为三步:

  • 为 uniqueInstance 分配内存
  • 初始化 uniqueInstance
  • 将 uniqueInstance 指向分配的内存所在
虽然正常顺序是 1 → 2 → 3,但 JVM 可能因指令重排导致实验顺序变为 1 → 3 → 2。
在单线程环境中这不会有问题,但在多线程环境下可能导致安全隐患:例如线程 A 实验了步骤 1 和 3,还未完成初始化(步骤 2),线程 B 看到 uniqueInstance 非空后直接使用它,结果是使用了未初始化的实例。
为避免这种情况,使用 volatile 关键字修饰 uniqueInstance,可以克制指令重排,确保多线程环境下实例的准确初始化和可见性,保证线程安全。
  1. package com;
  2. public class Singletion {
  3.    
  4.     private volatile static Singletion uniqueInstance;
  5.    
  6.     private Singletion(){};
  7.    
  8.     public static Singletion getUniqueInstance(){
  9.         if(uniqueInstance==null){
  10.             synchronized (Singletion.class){
  11.                 if(uniqueInstance==null){
  12.                     uniqueInstance=new Singletion();
  13.                 }
  14.             }
  15.         }
  16.         return uniqueInstance;
  17.     }
  18. }
复制代码
静态内部类实现(线程安全)


  • 延迟加载机制




    • 静态内部类 SingletonHolder 不会在类加载时初始化,只有在首次调用 getUniqueInstance() 方法并访问 SingletonHolder.INSTANCE 时才会被加载。
    • 此时 JVM 会保证 INSTANCE 的初始化过程是线程安全的,而且 仅实验一次。


  • 线程安全保证




    • 由于类加载机制的特性,JVM 会通过 类初始化锁(Class Initialization Lock) 确保 INSTANCE 的唯一性,无需额外同步代码。


  • 优势总结




    • 懒加载:实例仅在需要时创建,节省资源。
    • 线程安全:依赖 JVM 的类加载机制,无需双重查抄锁(DCL)或 synchronized。
    • 高性能:无锁竞争,访问服从高

  1. package com;
  2. public class Singletion {
  3.     private Singletion(){};
  4.     private static class SingletionHolder{
  5.         private static final Singletion INSTANCE=new Singletion()l
  6.     }
  7.     public static Singletion getUniqueInstance(){
  8.         return SingletionHolder.INSTANCE;
  9.     }
  10. }
复制代码
枚举类实现(线程安全)

枚举类的创建就是线程安全的,任何情况下都是单例的
枚举实现单例时,其实例的创建由 JVM 保证线程安全,且天然是单例。
长处



  • 写法简便
  • 天然线程安全
  • 主动防止反射和反序列化攻击
关于反序列化问题



  • 序列化:将 Java 对象转换为字节序列
  • 反序列化:根据字节序列重建 Java 对象
通例单例模式在反序列化时可能会创建新的实例,破坏单例性。
为了避免这一问题,通常需要重写 readResolve() 方法来确保反序列化返回同一个实例:
  1. package com;
  2. public enum Singletion {
  3.     INSTANCE;
  4.     // 添加业务逻辑方法
  5.     public void using() {
  6.         // 实际功能逻辑写在这里
  7.     }
  8. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

立山

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表