是设计模式,我们有救了!!!(四、原型模式)

通过复制现有对象来创建新对象,而不是通过新建类实例的方式。这种模式特别适用于创建成本较高的对象。

比如,你需要创建一个对象,但是这个对象的实际创建过程较为复杂,可能需要调用多个数据库,根据数据库里面的配置来进行生成。那么这个时候你就可以在初次创建了这个对象之后将其复制一份,缓存起来,下一次就可以使用缓存里面的数据了。但是实际使用的时候需要考虑到用版本号等机制保证一下缓存的一致性,这里只说明生成对象的方式。

原型模式在复制对象时的主要依赖的就是拷贝机制,这里我们用的都是浅拷贝。但是String对象比较例外,它具有不可变性,在复制的对象中的确只是复制了原有对象的string的引用。但是,如果原始对象中的string发生了修改,会给原始对象一个新的string。因此,变相的深拷贝的效果。

代码地址:github.com/YaYiXiBa/Ja...

scala 复制代码
public class Rectangle extends Shape{

    public Rectangle(){
         type = "Rectangle";
    }



    @Override
    void draw() {
        System.out.println("draw rectangle");
    }
}

首先,对不同的形状都进行了抽象。这样就只需要让抽象父类去实现Clonable接口就行了。

typescript 复制代码
public abstract class Shape implements Cloneable {
    private String id;
    protected String type;

    abstract void draw();


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getType() {
        return type;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object obj;
        obj = super.clone();
        return obj;
    }
}

重写Object的方法,如果有引用数据类型的话要记得使用深拷贝。

scss 复制代码
public class ShapeCache {
    private static Hashtable<String, Shape> shapeCache = new Hashtable<>();
    public static Shape getShape(String shapeId) {
        Shape shape = shapeCache.get(shapeId);
        try {
            return (Shape) shape.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

    public static void load() {
        Circle circle = new Circle();
        circle.setId("1");
        shapeCache.put(circle.getId(),circle);

        Square square = new Square();
        square.setId("2");
        shapeCache.put(square.getId(),square);

        Rectangle rectangle = new Rectangle();
        rectangle.setId("3");
        shapeCache.put(rectangle.getId(),rectangle);
    }
}

其实代码的核心步骤就是在return (Shape) shape.clone();虽然我们缓存了对象,但是不将原始对象返回,而是通过克隆返回新的对象,这是为了防止客户端修改对象,导致我们缓存的对象发生了变化。

ini 复制代码
public class Client {
    public static void main(String[] args) {
        ShapeCache.load();

        Shape clonedShape = (Shape) ShapeCache.getShape("1");
        System.out.println("Shape : " + clonedShape.getType());

        Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
        System.out.println("Shape : " + clonedShape2.getType());

        Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
        System.out.println("Shape : " + clonedShape3.getType());
        
        Shape circle1 = ShapeCache.getShape("1");
        Shape circle2 = ShapeCache.getShape("1");
        System.out.println(circle1 == circle2);
    }
}
输出结果:
Shape : Circle
Shape : Square
Shape : Rectangle
false
Process finished with exit code 0

可以发现circle1、circle2是不相等的。

原来我所以为的原型模式,就是我给对方一个对象,他返回给我一个一样的。现在才知道,以上写的是注册表的形式,通过ID来获取原型。。。。

相关推荐
高频因子挖掘机1 小时前
实时行情为什么不应该逐只股票请求?批量查询与标的池管理实践
后端·github·api
程序猿DD6 小时前
OctaFuse Gateway 2.15.0:MCP 聚合、向量 Embeddings 与官方目录同步
后端·agent
余槐i9 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
需要8269 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
凤山老林10 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
伯恩bourne11 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
张彦峰ZYF11 小时前
停顿短不等于延迟低:G1、ZGC 与低延迟服务的目标分野、代价账本与选型标定
后端·回收暂停、应用停止总时长·到达安全点、分配停滞·屏障吃吞吐、并发线程吃核心·并发窗口吃堆余量·分区式靠挑回收集兑现目标·染色指针式不支持压缩引用
pride.li12 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
upala12 小时前
【仓颉语言入门 · 第二篇 第 6 课】
后端
罗丹丹Luna12 小时前
移动端显示“已提交”以后:SAP 与低代码集成该怎样暴露真实状态
后端·架构