原型模式 (Prototype Pattern)

模式概述 (Pattern Overview)

原型模式是一种创建型设计模式,它使你能够复制已有对象,而无需使代码依赖它们所属的类。

意图 (Intent)

用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

适用场景 (When to Use)

  • 当系统应该独立于它的产品创建、构成和表示时
  • 当要实例化的类是在运行时刻指定时,例如通过动态装载
  • 为了避免创建一个与产品类层次平行的工厂类层次时
  • 当一个类的实例只能有几个不同状态组合中的一种时

UML类图 (UML Class Diagram)

uses
«interface»
Prototype
+clone()
ConcretePrototype1
-field1: String
-field2: int
+clone()
+deepClone()
ConcretePrototype2
-field3: double
-field4: List<String>
+clone()
+deepClone()
Client
-prototype: Prototype
+operation()

实现方式 (Implementation Approaches)

1. 浅克隆 (Shallow Clone)

/**
 * 原型接口
 * Prototype Interface
 */
public interface Prototype {
    Prototype clone();
}

/**
 * 具体原型类 - 文档
 * Concrete Prototype Class - Document
 */
public class Document implements Prototype, Cloneable {
    private String title;
    private String content;
    private List<String> authors;
    private Date creationDate;
    
    public Document(String title, String content, List<String> authors) {
        this.title = title;
        this.content = content;
        this.authors = new ArrayList<>(authors);
        this.creationDate = new Date();
    }
    
    /**
     * 浅克隆实现
     * Shallow clone implementation
     */
    @Override
    public Prototype clone() {
        try {
            // 调用Object的clone方法
            Document cloned = (Document) super.clone();
            // 注意:authors列表是浅复制
            return cloned;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException("克隆失败", e);
        }
    }
    
    /**
     * 深克隆实现
     * Deep clone implementation
     */
    public Document deepClone() {
        try {
            Document cloned = (Document) super.clone();
            // 深复制authors列表
            cloned.authors = new ArrayList<>(this.authors);
            // 深复制日期
            cloned.creationDate = new Date(this.creationDate.getTime());
            return cloned;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException("深克隆失败", e);
        }
    }
    
    // Getters and setters
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    
    public String getContent() { return content; }
    public void setContent(String content) { this.content = content; }
    
    public List<String> getAuthors() { return authors; }
    public void setAuthors(List<String> authors) { this.authors = authors; }
    
    public Date getCreationDate() { return creationDate; }
    public void setCreationDate(Date creationDate) { this.creationDate = creationDate; }
    
    @Override
    public String toString() {
        return "Document{" +
                "title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", authors=" + authors +
                ", creationDate=" + creationDate +
                '}';
    }
}

/**
 * 客户端代码
 * Client Code
 */
public class PrototypeClient {
    public static void main(String[] args) {
        // 创建原始文档
        List<String> authors = Arrays.asList("张三", "李四");
        Document originalDoc = new Document("设计文档", "这是一个重要的设计文档", authors);
        System.out.println("原始文档: " + originalDoc);
        
        // 浅克隆
        Document shallowClone = (Document) originalDoc.clone();
        System.out.println("浅克隆文档: " + shallowClone);
        
        // 修改克隆文档的内容
        shallowClone.setTitle("修改后的设计文档");
        shallowClone.getAuthors().add("王五"); // 这会影响原始文档!
        
        System.out.println("\n修改后:");
        System.out.println("原始文档: " + originalDoc);
        System.out.println("浅克隆文档: " + shallowClone);
        
        System.out.println("\n--- 深克隆演示 ---\n");
        
        // 深克隆
        Document deepClone = originalDoc.deepClone();
        deepClone.setTitle("深克隆设计文档");
        deepClone.getAuthors().add("赵六"); // 这不会影响原始文档
        
        System.out.println("原始文档: " + originalDoc);
        System.out.println("深克隆文档: " + deepClone);
    }
}

2. 序列化实现深克隆 (Serialization-based Deep Clone)

import java.io.*;
import java.util.*;

/**
 * 使用序列化实现深克隆的工具类
 * Utility class for deep cloning using serialization
 */
public class SerializationUtils {
    
    /**
     * 深克隆对象
     * Deep clone an object
     */
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T deepClone(T object) {
        try {
            // 将对象写入字节数组输出流
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(object);
            oos.flush();
            oos.close();
            
            // 从字节数组输入流读取对象
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            T clonedObject = (T) ois.readObject();
            ois.close();
            
            return clonedObject;
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException("深克隆失败", e);
        }
    }
}

/**
 * 可序列化的复杂对象
 * Serializable Complex Object
 */
public class ComplexObject implements Serializable {
    private String name;
    private int age;
    private List<String> hobbies;
    private Map<String, Object> attributes;
    private NestedObject nestedObject;
    
    public ComplexObject(String name, int age) {
        this.name = name;
        this.age = age;
        this.hobbies = new ArrayList<>();
        this.attributes = new HashMap<>();
        this.nestedObject = new NestedObject("nested");
    }
    
    // 使用序列化工具进行深克隆
    public ComplexObject deepClone() {
        return SerializationUtils.deepClone(this);
    }
    
    // Getters and setters
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    
    public List<String> getHobbies() { return hobbies; }
    public void setHobbies(List<String> hobbies) { this.hobbies = hobbies; }
    
    public Map<String, Object> getAttributes() { return attributes; }
    public void setAttributes(Map<String, Object> attributes) { this.attributes = attributes; }
    
    public NestedObject getNestedObject() { return nestedObject; }
    public void setNestedObject(NestedObject nestedObject) { this.nestedObject = nestedObject; }
    
    @Override
    public String toString() {
        return "ComplexObject{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", hobbies=" + hobbies +
                ", attributes=" + attributes +
                ", nestedObject=" + nestedObject +
                '}';
    }
}

/**
 * 嵌套对象
 * Nested Object
 */
class NestedObject implements Serializable {
    private String data;
    
    public NestedObject(String data) {
        this.data = data;
    }
    
    public String getData() { return data; }
    public void setData(String data) { this.data = data; }
    
    @Override
    public String toString() {
        return "NestedObject{" +
                "data='" + data + '\'' +
                '}';
    }
}

/**
 * 客户端代码
 * Client Code
 */
public class SerializationCloneClient {
    public static void main(String[] args) {
        // 创建复杂对象
        ComplexObject original = new ComplexObject("张三", 25);
        original.getHobbies().add("读书");
        original.getHobbies().add("游泳");
        original.getAttributes().put("city", "北京");
        original.getAttributes().put("profession", "工程师");
        
        System.out.println("原始对象: " + original);
        
        // 深克隆
        ComplexObject cloned = original.deepClone();
        
        // 修改克隆对象
        cloned.setName("李四");
        cloned.getHobbies().add("编程");
        cloned.getAttributes().put("city", "上海");
        cloned.getNestedObject().setData("modified nested");
        
        System.out.println("\n修改后的克隆对象: " + cloned);
        System.out.println("原始对象: " + original);
        
        // 验证深克隆成功 - 原始对象不受影响
        System.out.println("\n验证深克隆:");
        System.out.println("原始对象hobbies数量: " + original.getHobbies().size());
        System.out.println("克隆对象hobbies数量: " + cloned.getHobbies().size());
        System.out.println("原始对象city: " + original.getAttributes().get("city"));
        System.out.println("克隆对象city: " + cloned.getAttributes().get("city"));
    }
}

3. 原型注册表 (Prototype Registry)

import java.util.*;

/**
 * 原型接口
 * Prototype Interface
 */
public interface Shape extends Cloneable {
    Shape clone();
    void draw();
    double getArea();
}

/**
 * 具体原型 - 圆形
 * Concrete Prototype - Circle
 */
public class Circle implements Shape {
    private double radius;
    private String color;
    
    public Circle(double radius, String color) {
        this.radius = radius;
        this.color = color;
    }
    
    @Override
    public Shape clone() {
        try {
            return (Circle) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException("克隆失败", e);
        }
    }
    
    @Override
    public void draw() {
        System.out.println("绘制" + color + "圆形,半径: " + radius);
    }
    
    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
    
    public void setRadius(double radius) { this.radius = radius; }
    public void setColor(String color) { this.color = color; }
}

/**
 * 具体原型 - 矩形
 * Concrete Prototype - Rectangle
 */
public class Rectangle implements Shape {
    private double width;
    private double height;
    private String color;
    
    public Rectangle(double width, double height, String color) {
        this.width = width;
        this.height = height;
        this.color = color;
    }
    
    @Override
    public Shape clone() {
        try {
            return (Rectangle) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException("克隆失败", e);
        }
    }
    
    @Override
    public void draw() {
        System.out.println("绘制" + color + "矩形,宽: " + width + ", 高: " + height);
    }
    
    @Override
    public double getArea() {
        return width * height;
    }
    
    public void setWidth(double width) { this.width = width; }
    public void setHeight(double height) { this.height = height; }
    public void setColor(String color) { this.color = color; }
}

/**
 * 原型注册表
 * Prototype Registry
 */
public class ShapeRegistry {
    private Map<String, Shape> prototypes = new HashMap<>();
    
    /**
     * 注册原型
     * Register prototype
     */
    public void registerPrototype(String key, Shape prototype) {
        prototypes.put(key, prototype);
    }
    
    /**
     * 获取原型
     * Get prototype
     */
    public Shape getPrototype(String key) {
        Shape prototype = prototypes.get(key);
        if (prototype == null) {
            throw new IllegalArgumentException("未找到原型: " + key);
        }
        return prototype.clone();
    }
    
    /**
     * 获取所有原型键
     * Get all prototype keys
     */
    public Set<String> getPrototypeKeys() {
        return prototypes.keySet();
    }
}

/**
 * 客户端代码
 * Client Code
 */
public class PrototypeRegistryClient {
    public static void main(String[] args) {
        // 创建原型注册表
        ShapeRegistry registry = new ShapeRegistry();
        
        // 注册原型
        registry.registerPrototype("red-circle", new Circle(5.0, "红色"));
        registry.registerPrototype("blue-circle", new Circle(3.0, "蓝色"));
        registry.registerPrototype("green-rectangle", new Rectangle(4.0, 6.0, "绿色"));
        registry.registerPrototype("yellow-rectangle", new Rectangle(2.0, 3.0, "黄色"));
        
        System.out.println("可用原型: " + registry.getPrototypeKeys());
        
        // 使用原型创建对象
        Shape redCircle = registry.getPrototype("red-circle");
        redCircle.draw();
        System.out.println("面积: " + redCircle.getArea());
        
        // 修改克隆对象
        Shape modifiedCircle = registry.getPrototype("red-circle");
        modifiedCircle.setRadius(10.0);
        modifiedCircle.setColor("紫色");
        modifiedCircle.draw();
        
        // 创建多个矩形
        for (int i = 0; i < 3; i++) {
            Shape rectangle = registry.getPrototype("green-rectangle");
            rectangle.setWidth(rectangle.getArea() / (i + 1)); // 修改宽度
            rectangle.draw();
        }
    }
}

知名框架案例 (Framework Examples)

1. Spring Framework - @Scope(“prototype”)

/**
 * Spring中原型作用域的使用
 * Prototype Scope Usage in Spring
 */
@Component
public class SpringPrototypeExample {
    
    /**
     * 原型Bean - 每次注入都创建新实例
     * Prototype Bean - New instance created on each injection
     */
    @Component
    @Scope("prototype")
    public static class PrototypeBean {
        private final String id = UUID.randomUUID().toString();
        private final Date creationTime = new Date();
        
        @PostConstruct
        public void init() {
            System.out.println("原型Bean创建: " + id + " at " + creationTime);
        }
        
        public String getId() { return id; }
        public Date getCreationTime() { return creationTime; }
    }
    
    /**
     * 单例Bean - 使用原型Bean
     * Singleton Bean - Using Prototype Bean
     */
    @Component
    public static class SingletonBean {
        
        @Autowired
        private ApplicationContext applicationContext;
        
        public void demonstratePrototype() {
            System.out.println("\n=== 演示原型作用域 ===");
            
            // 每次getBean都会创建新的原型实例
            PrototypeBean bean1 = applicationContext.getBean(PrototypeBean.class);
            PrototypeBean bean2 = applicationContext.getBean(PrototypeBean.class);
            PrototypeBean bean3 = applicationContext.getBean(PrototypeBean.class);
            
            System.out.println("Bean1 ID: " + bean1.getId());
            System.out.println("Bean2 ID: " + bean2.getId());
            System.out.println("Bean3 ID: " + bean3.getId());
            
            // 验证它们是不同的实例
            System.out.println("bean1 == bean2: " + (bean1 == bean2));
            System.out.println("bean1.equals(bean2): " + bean1.equals(bean2));
        }
    }
    
    /**
     * 原型工厂方法
     * Prototype Factory Method
     */
    @Configuration
    public static class PrototypeConfig {
        
        @Bean
        @Scope("prototype")
        public RequestContext requestContext() {
            return new RequestContext(UUID.randomUUID().toString(), new Date());
        }
        
        @Bean
        @Scope("prototype")
        public ProcessingContext processingContext(String requestId) {
            ProcessingContext context = new ProcessingContext();
            context.setRequestId(requestId);
            context.setStartTime(System.currentTimeMillis());
            return context;
        }
    }
    
    @Data
    @AllArgsConstructor
    public static class RequestContext {
        private String requestId;
        private Date timestamp;
    }
    
    @Data
    public static class ProcessingContext {
        private String requestId;
        private long startTime;
        private Map<String, Object> attributes = new HashMap<>();
    }
}

2. Netty - ChannelConfig

/**
 * Netty中ChannelConfig的原型模式使用
 * Prototype Pattern usage of ChannelConfig in Netty
 */
public class NettyPrototypeExample {
    
    public static void main(String[] args) {
        // 创建基础配置
        ChannelConfig baseConfig = new DefaultChannelConfig(null);
        baseConfig.setOption(ChannelOption.SO_BACKLOG, 128);
        baseConfig.setOption(ChannelOption.SO_KEEPALIVE, true);
        baseConfig.setOption(ChannelOption.TCP_NODELAY, true);
        
        // 创建ServerBootstrap并复制配置
        ServerBootstrap bootstrap1 = new ServerBootstrap();
        bootstrap1.option(ChannelOption.SO_BACKLOG, 128)
                 .option(ChannelOption.SO_KEEPALIVE, true)
                 .option(ChannelOption.TCP_NODELAY, true);
        
        ServerBootstrap bootstrap2 = new ServerBootstrap();
        bootstrap2.option(ChannelOption.SO_BACKLOG, 256)  // 不同的配置
                 .option(ChannelOption.SO_KEEPALIVE, true)
                 .option(ChannelOption.TCP_NODELAY, true);
        
        // 基于原型创建多个相似的配置
        Map<ChannelOption<?>, Object> baseOptions = new HashMap<>();
        baseOptions.put(ChannelOption.SO_BACKLOG, 128);
        baseOptions.put(ChannelOption.SO_KEEPALIVE, true);
        baseOptions.put(ChannelOption.TCP_NODELAY, true);
        
        // 创建多个ServerBootstrap,基于相同的原型配置
        for (int i = 0; i < 3; i++) {
            final int port = 8080 + i;
            ServerBootstrap bootstrap = new ServerBootstrap();
            
            // 复制基础配置
            baseOptions.forEach(bootstrap::option);
            
            // 添加特定的配置
            bootstrap.option(ChannelOption.SO_RCVBUF, 1024 * (i + 1));
            
            bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup())
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) {
                            ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
                                @Override
                                protected void channelRead0(ChannelHandlerContext ctx, String msg) {
                                    System.out.println("Port " + port + " received: " + msg);
                                }
                            });
                        }
                    });
            
            bootstrap.bind(port).addListener(future -> {
                if (future.isSuccess()) {
                    System.out.println("Server started on port " + port);
                }
            });
        }
    }
    
    /**
     * 自定义原型配置
     * Custom Prototype Configuration
     */
    public static class PrototypeChannelConfig {
        private final Map<ChannelOption<?>, Object> options;
        
        public PrototypeChannelConfig() {
            this.options = new HashMap<>();
            // 设置默认配置
            options.put(ChannelOption.SO_BACKLOG, 128);
            options.put(ChannelOption.SO_KEEPALIVE, true);
            options.put(ChannelOption.TCP_NODELAY, true);
        }
        
        public PrototypeChannelConfig copy() {
            PrototypeChannelConfig copy = new PrototypeChannelConfig();
            copy.options.putAll(this.options);
            return copy;
        }
        
        public PrototypeChannelConfig withOption(ChannelOption<?> option, Object value) {
            PrototypeChannelConfig copy = this.copy();
            copy.options.put(option, value);
            return copy;
        }
        
        public void applyTo(ServerBootstrap bootstrap) {
            options.forEach(bootstrap::option);
        }
    }
}

3. MyBatis - CacheKey

/**
 * MyBatis中CacheKey的原型模式使用
 * Prototype Pattern usage of CacheKey in MyBatis
 */
public class MyBatisCacheKeyExample {
    
    /**
     * 演示CacheKey的克隆
     * Demonstrate CacheKey cloning
     */
    public static void demonstrateCacheKeyClone() {
        // 创建原始CacheKey
        CacheKey originalKey = new CacheKey();
        originalKey.update("select * from users");
        originalKey.update(1); // 参数1
        originalKey.update("active"); // 参数2
        
        System.out.println("原始CacheKey: " + originalKey);
        System.out.println("原始CacheKey哈希值: " + originalKey.hashCode());
        
        // 克隆CacheKey
        CacheKey clonedKey = originalKey.clone();
        
        System.out.println("克隆CacheKey: " + clonedKey);
        System.out.println("克隆CacheKey哈希值: " + clonedKey.hashCode());
        System.out.println("CacheKey相等: " + originalKey.equals(clonedKey));
        
        // 修改克隆的CacheKey
        clonedKey.update("modified");
        System.out.println("修改后的克隆CacheKey: " + clonedKey);
        System.out.println("原始CacheKey不受影响: " + originalKey);
    }
    
    /**
     * 自定义缓存键建造者
     * Custom Cache Key Builder
     */
    public static class CacheKeyBuilder {
        private String statement;
        private List<Object> parameters = new ArrayList<>();
        private int offset = 0;
        private int limit = Integer.MAX_VALUE;
        
        public CacheKeyBuilder statement(String statement) {
            this.statement = statement;
            return this;
        }
        
        public CacheKeyBuilder parameter(Object parameter) {
            this.parameters.add(parameter);
            return this;
        }
        
        public CacheKeyBuilder parameters(Object... params) {
            this.parameters.addAll(Arrays.asList(params));
            return this;
        }
        
        public CacheKeyBuilder pagination(int offset, int limit) {
            this.offset = offset;
            this.limit = limit;
            return this;
        }
        
        public CacheKey build() {
            CacheKey cacheKey = new CacheKey();
            cacheKey.update(statement);
            
            for (Object param : parameters) {
                cacheKey.update(param);
            }
            
            cacheKey.update(offset);
            cacheKey.update(limit);
            
            return cacheKey;
        }
        
        public CacheKey buildFromPrototype(CacheKey prototype) {
            CacheKey newKey = prototype.clone();
            newKey.update(statement);
            
            for (Object param : parameters) {
                newKey.update(param);
            }
            
            newKey.update(offset);
            newKey.update(limit);
            
            return newKey;
        }
    }
}

4. Logback - LoggingEvent

/**
 * Logback中LoggingEvent的原型模式概念
 * Prototype Pattern concept in LoggingEvent of Logback
 */
public class LogbackEventExample {
    
    /**
     * 自定义日志事件原型
     * Custom Logging Event Prototype
     */
    public static class LoggingEventPrototype implements Cloneable {
        private String loggerName;
        private Level level;
        private String message;
        private long timestamp;
        private Map<String, String> mdc;
        private List<Object> arguments;
        
        public LoggingEventPrototype(String loggerName, Level level, String message) {
            this.loggerName = loggerName;
            this.level = level;
            this.message = message;
            this.timestamp = System.currentTimeMillis();
            this.mdc = new HashMap<>();
            this.arguments = new ArrayList<>();
        }
        
        @Override
        public LoggingEventPrototype clone() {
            try {
                LoggingEventPrototype cloned = (LoggingEventPrototype) super.clone();
                // 深复制MDC和参数列表
                cloned.mdc = new HashMap<>(this.mdc);
                cloned.arguments = new ArrayList<>(this.arguments);
                cloned.timestamp = System.currentTimeMillis();
                return cloned;
            } catch (CloneNotSupportedException e) {
                throw new RuntimeException("克隆失败", e);
            }
        }
        
        // 建造者模式结合原型模式
        public static class Builder {
            private String loggerName;
            private Level level;
            private String message;
            private Map<String, String> mdc = new HashMap<>();
            private List<Object> arguments = new ArrayList<>();
            
            public Builder loggerName(String loggerName) {
                this.loggerName = loggerName;
                return this;
            }
            
            public Builder level(Level level) {
                this.level = level;
                return this;
            }
            
            public Builder message(String message) {
                this.message = message;
                return this;
            }
            
            public Builder mdc(String key, String value) {
                this.mdc.put(key, value);
                return this;
            }
            
            public Builder argument(Object arg) {
                this.arguments.add(arg);
                return this;
            }
            
            public LoggingEventPrototype build() {
                LoggingEventPrototype event = new LoggingEventPrototype(loggerName, level, message);
                event.mdc.putAll(this.mdc);
                event.arguments.addAll(this.arguments);
                return event;
            }
            
            public LoggingEventPrototype buildFromPrototype(LoggingEventPrototype prototype) {
                LoggingEventPrototype event = prototype.clone();
                if (loggerName != null) event.loggerName = loggerName;
                if (level != null) event.level = level;
                if (message != null) event.message = message;
                event.mdc.putAll(this.mdc);
                event.arguments.addAll(this.arguments);
                return event;
            }
        }
        
        // Getters
        public String getLoggerName() { return loggerName; }
        public Level getLevel() { return level; }
        public String getMessage() { return message; }
        public long getTimestamp() { return timestamp; }
        public Map<String, String> getMdc() { return new HashMap<>(mdc); }
        public List<Object> getArguments() { return new ArrayList<>(arguments); }
        
        @Override
        public String toString() {
            return "LoggingEventPrototype{" +
                    "loggerName='" + loggerName + '\'' +
                    ", level=" + level +
                    ", message='" + message + '\'' +
                    ", timestamp=" + timestamp +
                    ", mdc=" + mdc +
                    ", arguments=" + arguments +
                    '}';
        }
    }
    
    public static void main(String[] args) {
        // 创建原型
        LoggingEventPrototype prototype = new LoggingEventPrototype("com.example", Level.INFO, "应用启动");
        prototype.getMdc().put("requestId", "12345");
        prototype.getArguments().add("arg1");
        
        System.out.println("原始原型: " + prototype);
        
        // 克隆原型
        LoggingEventPrototype cloned = prototype.clone();
        cloned.setMessage("应用运行中");
        cloned.getMdc().put("userId", "user123");
        
        System.out.println("克隆对象: " + cloned);
        System.out.println("原始原型: " + prototype);
    }
}

5. Hibernate - Query

/**
 * Hibernate中Query的原型模式使用
 * Prototype Pattern usage of Query in Hibernate
 */
public class HibernateQueryExample {
    
    /**
     * 自定义查询原型
     * Custom Query Prototype
     */
    public static class QueryPrototype implements Cloneable {
        private String hql;
        private Map<String, Object> parameters = new HashMap<>();
        private int firstResult = 0;
        private int maxResults = -1;
        private boolean cacheable = false;
        private String cacheRegion;
        
        public QueryPrototype(String hql) {
            this.hql = hql;
        }
        
        @Override
        public QueryPrototype clone() {
            try {
                QueryPrototype cloned = (QueryPrototype) super.clone();
                cloned.parameters = new HashMap<>(this.parameters);
                return cloned;
            } catch (CloneNotSupportedException e) {
                throw new RuntimeException("克隆失败", e);
            }
        }
        
        // 建造者模式结合原型模式
        public static class Builder {
            private String hql;
            private Map<String, Object> parameters = new HashMap<>();
            private int firstResult = 0;
            private int maxResults = -1;
            private boolean cacheable = false;
            private String cacheRegion;
            
            public Builder(String hql) {
                this.hql = hql;
            }
            
            public Builder parameter(String name, Object value) {
                this.parameters.put(name, value);
                return this;
            }
            
            public Builder parameters(Map<String, Object> params) {
                this.parameters.putAll(params);
                return this;
            }
            
            public Builder firstResult(int firstResult) {
                this.firstResult = firstResult;
                return this;
            }
            
            public Builder maxResults(int maxResults) {
                this.maxResults = maxResults;
                return this;
            }
            
            public Builder cacheable(boolean cacheable) {
                this.cacheable = cacheable;
                return this;
            }
            
            public Builder cacheRegion(String cacheRegion) {
                this.cacheRegion = cacheRegion;
                return this;
            }
            
            public QueryPrototype build() {
                QueryPrototype query = new QueryPrototype(hql);
                query.parameters.putAll(this.parameters);
                query.firstResult = this.firstResult;
                query.maxResults = this.maxResults;
                query.cacheable = this.cacheable;
                query.cacheRegion = this.cacheRegion;
                return query;
            }
            
            public QueryPrototype buildFromPrototype(QueryPrototype prototype) {
                QueryPrototype query = prototype.clone();
                if (hql != null) query.hql = hql;
                query.parameters.putAll(this.parameters);
                if (firstResult != 0) query.firstResult = this.firstResult;
                if (maxResults != -1) query.maxResults = this.maxResults;
                query.cacheable = this.cacheable;
                query.cacheRegion = this.cacheRegion;
                return query;
            }
        }
        
        // Getters and business methods
        public String getHql() { return hql; }
        public Map<String, Object> getParameters() { return new HashMap<>(parameters); }
        public int getFirstResult() { return firstResult; }
        public int getMaxResults() { return maxResults; }
        public boolean isCacheable() { return cacheable; }
        public String getCacheRegion() { return cacheRegion; }
        
        public void setParameter(String name, Object value) {
            this.parameters.put(name, value);
        }
        
        public void execute() {
            System.out.println("执行查询: " + hql);
            System.out.println("参数: " + parameters);
            System.out.println("分页: " + firstResult + ", " + maxResults);
            System.out.println("缓存: " + cacheable + ", " + cacheRegion);
        }
        
        @Override
        public String toString() {
            return "QueryPrototype{" +
                    "hql='" + hql + '\'' +
                    ", parameters=" + parameters +
                    ", firstResult=" + firstResult +
                    ", maxResults=" + maxResults +
                    ", cacheable=" + cacheable +
                    ", cacheRegion='" + cacheRegion + '\'' +
                    '}';
        }
    }
    
    public static void main(String[] args) {
        // 创建基础查询原型
        QueryPrototype baseQuery = new QueryPrototype("FROM User u WHERE u.status = :status");
        baseQuery.setParameter("status", "active");
        baseQuery.setCacheable(true);
        
        System.out.println("基础查询原型: " + baseQuery);
        
        // 基于原型创建不同的查询
        QueryPrototype pagedQuery = baseQuery.clone();
        pagedQuery.setParameter("page", 1);
        pagedQuery.setFirstResult(0);
        pagedQuery.setMaxResults(10);
        
        QueryPrototype cachedQuery = baseQuery.clone();
        cachedQuery.setCacheRegion("user-cache");
        cachedQuery.setParameter("sort", "name");
        
        System.out.println("分页查询: " + pagedQuery);
        System.out.println("缓存查询: " + cachedQuery);
        System.out.println("基础查询原型: " + baseQuery);
    }
}

优缺点分析 (Pros and Cons Analysis)

优点 (Advantages)

  1. 性能提升:避免重复创建相似对象的开销
  2. 简化对象创建:隐藏对象创建的细节
  3. 运行时灵活性:可以在运行时动态创建对象
  4. 减少子类数量:避免创建大量相似的子类
  5. 动态配置:可以动态地添加或删除原型

缺点 (Disadvantages)

  1. 深克隆复杂性:实现深克隆可能很复杂
  2. 循环引用问题:需要处理循环引用的情况
  3. 初始化复杂性:每个原型都需要适当的初始化
  4. 内存开销:需要维护原型注册表
  5. 克隆限制:某些对象可能无法克隆

使用场景 (Use Cases)

适用场景

  • 系统需要独立于产品的创建、构成和表示时
  • 要实例化的类在运行时刻指定时
  • 避免创建与产品类层次平行的工厂类层次时
  • 类的实例只能有几个不同状态组合中的一种时
  • 对象创建成本高,需要重复使用相似对象时

不适用场景

  • 对象的创建成本很低
  • 对象的状态变化频繁
  • 对象包含循环引用且无法处理
  • 系统不需要运行时动态创建对象

最佳实践 (Best Practices)

  1. 使用Cloneable接口:确保对象正确实现Cloneable接口
  2. 处理深克隆:正确实现深克隆以避免共享引用
  3. 考虑序列化:对于复杂的深克隆,考虑使用序列化
  4. 原型注册表:使用注册表管理原型对象
  5. 初始化状态:确保原型对象有合适的初始状态
  6. 性能考虑:在性能敏感的场景下评估克隆成本

与其他模式的关系 (Relationship with Other Patterns)

与工厂模式的关系

  • 工厂模式:基于继承,通过子类创建对象
  • 原型模式:基于克隆,通过复制现有对象创建新对象

与建造者模式的关系

  • 建造者模式可以用来创建复杂的原型对象

与单例模式的关系

  • 原型注册表通常使用单例模式实现

总结 (Summary)

原型模式是一种强大的创建型设计模式,它通过复制现有对象来创建新对象,而不是通过实例化类。这种模式特别适合以下场景:创建对象成本高、需要动态指定对象类型、避免创建大量相似子类、以及对象状态组合有限的情况。

在Spring、Netty、MyBatis等知名框架中,原型模式被广泛应用于管理对象生命周期、配置复制、缓存键创建等场景。理解原型模式的实现原理和适用场景,对于编写高效、灵活的Java应用程序至关重要。正确使用原型模式可以显著提高系统性能和可维护性。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐