解密原型模式:工作原理与实际应用

推荐语

本文深入浅出地介绍了原型模式,一种常用的设计模式,帮助读者全面了解其工作原理和实际应用。通过实例演示,读者将学到如何使用原型模式来高效地复用代码、简化对象创建过程,并提升产品质量和可维护性。如果您正在寻找一种能够优化软件开发的方法,不妨一试原型模式。阅读本文,一定会让您受益匪浅!

什么是原型模式

原型模式是一种创建型模式,它允许通过复制现有对象来创建新对象,而无需从头开始创建全新的对象。这种模式在软件系统中应用很广泛,特别是在需要创建大量相似或相同对象的情况下。

这种模式的主要想法是,在某个类(称为"原型类")中定义一个方法,该方法用于创建并返回该类的另一个实例。这个新实例是原型的复制品,通过复制现有的对象来创建,而不是通过使用构造函数来创建新的对象。

原型模式的核心原理

原型模式的核心原理是通过复制现有对象来创建新对象,而无需依赖具体的类实例化过程。它允许在运行时动态创建对象,并通过克隆来生成新的实例。

具体而言,原型模式通过定义一个原型对象作为创建其他对象的基础。原型对象是通过克隆(浅克隆或深克隆)来生成新对象的模板,新对象将具备与原型对象相同或部分相同的属性和方法。这种方式避免了显式地依赖于特定类的实例化过程,使得系统更加灵活、可扩展。

核心原理可以总结为:通过克隆现有对象来创建新对象,以实现对象的复用和动态创建。原型模式的核心角色:

原型对象

在原型模式中,通过复制这个原型对象来创建新的对象。这个原型对象可以是任何类型的对象,包括基本数据类型、自定义对象、集合等。

抽象原型

抽象原型角色定义了原型对象的通用接口和行为

具体原型

具体原型角色实现了抽象原型角色所定义的接口和行为,并提供了具体的实现细节。

在Java中,Cloneable接口是一个标记接口,用于指示一个对象可以被复制。它没有任何方法,只是一个标识符,用于指示实现Cloneable接口的类应该实现自己的复制方法。

要使一个对象可复制,需要实现clone()方法。该方法应该在类中定义为public和protected,并使用super.clone()调用超类的clone()方法来创建并返回一个新对象。新对象应该是原始对象的一个副本,包括所有字段和属性的副本。

原型模式的实际示例

机器狗这种玩意,其实在很早以前就被发明并制造出来了,小米科技也搞了一款,目前在官网上已经迭代到第二代了,你敢信这玩意居然卖到了12999元!可能有什么高科技在里面?

虽然这玩意能后空翻,但还是有点贵,这里咱们就用原型模式把价格打下来!

  1. 抽象产品类:Dog.java
csharp 复制代码
public interface Dog extends Cloneable {
    /**
     * 奔跑
     */
    void run();

    /**
     * 后空翻
     */
    void backflip();
}
  1. 具体产品类:RoboticDog.java
typescript 复制代码
public class RoboticDog implements Dog{

    private String name="铁蛋";

    @Override
    protected Dog clone() throws CloneNotSupportedException {
        return (Dog) super.clone();
    }

    @Override
    public void run() {
        System.out.println(this.name+"在奔跑");
    }

    @Override
    public void backflip() {
        System.out.println(this.name+"在表演后空翻");
    }
}
  1. 简单工厂类,用于批量生产机器狗这款产品,DamiFactory.java
kotlin 复制代码
public class DaMiFactory {
    private Dog dog;

    public DaMiFactory(Dog dog) {
        this.dog = dog;
    }

    public Dog batchProduce(){
        if (dog != null&&dog instanceof RoboticDog) {
            try {
                return ((RoboticDog) dog).clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
  1. 测试类
ini 复制代码
public class Test
{
    public static void main(String[] args) {
        Dog roboticDog=new RoboticDog();
        DaMiFactory daMiFactory = new DaMiFactory(roboticDog);
        //开始批量生产
        for (int i = 0; i < 1000; i++) {
            System.out.println("第"+(i+1)+"只:");
            Dog dog = daMiFactory.batchProduce();
            dog.run();
            dog.backflip();
        }

    }
}

原型模式的应用场景

在以下场景中,可以考虑使用原型模式:

  1. 资源优化场景:当一个类初始化时需要消化大量资源,包括数据、硬件资源等,这时就可以使用原型模式来避免资源的浪费。
  2. 性能和安全要求的场景:如果通过"new"产生一个对象需要非常繁琐的数据准备或访问权限,那么可以使用原型模式来提高性能并增强安全性。
  3. 动态指定实例化类:当需要实例化的类在运行时刻动态指定时,可以使用原型模式。通过克隆原型来得到需要的实例,可以避免在运行时指定具体的类。
  4. 处理复杂对象:如果处理的对象比较简单,并且对象之间的区别很小,可能只是很固定的几个属性不同,那么使用原型模式更合适。例如生活中的彩虹的七彩颜色,只需要根据现有的一个颜色对象,克隆一个新的颜色对象,然后修改具体的颜色的值就可以满足要求。
  5. 多线程环境:在多线程环境中,由于线程之间共享数据可能会导致数据的不一致,这时可以使用原型模式。通过在原型对象上进行复制产生新的实例,可以避免线程之间的互相影响。
  6. 网络连接池:当需要频繁实例化并销毁对象时,如多线程的线程池、网络连接池等,使用原型模式可以避免频繁的创建和销毁对象,提高性能。

在实际项目中,原型模式通常会和工厂方法模式一起出现,由工厂方法模式通过"clone"方法创建对象,然后提供给调用者。

总结

总的来说,原型模式是一种非常实用的创建型模式,它可以在很多情况下提高代码的效率和复用性,在使用原型模式的时候需要特别注意使用场景。优点与缺点总是相对而言的,在某些场景下,原来的优点可能就变成缺点了,而在另外一些场景,缺点也有可能会变成优点,因此辩证的去理解,从实际出发做合理选择,这是根本目的。

优点

  1. 原型模式的主要优点是性能和资源利用率,由于对象是在已有实例的基础上创建的,因此不需要为每个新对象分配内存和计算资源,这可以提高应用程序的性能和资源利用率。
  2. 原型模式可以在运行时动态创建对象,无需在编译时确定对象的类型。
  3. 通过复制现有对象来创建新对象,可以避免重新编写相同的代码,提高代码的复用性。
  4. 由于新对象是通过复制现有对象来创建的,因此新对象与原对象具有相同的属性和行为,但它们是相互独立的,可以对其中一个进行修改而不会影响到另一个。

缺点

  1. 原型模式可能会导致内存占用增加,因为每次创建新对象时都需要复制原型对象。
  2. 如果原型对象的结构非常复杂,那么复制原型对象可能会变得非常耗时。
  3. 原型模式可能会违反单一责任原则,因为类可能需要同时实现其应用逻辑和原型创建逻辑。
  4. 由于对象是通过复制现有的实例来创建的,因此修改一个原型可能会影响到所有的副本。
  5. 由于所有的对象都是从一个原型创建的,因此所有的对象可能会有相同的属性和行为,这可能会限制应用程序的灵活性和可扩展性。

写在最后

感谢您阅读我们的文章!如果您觉得这篇文章对您有所帮助、内容丰富、或者仅仅是让您感到轻松愉快,请不要吝啬您的点赞。您的赞和支持是我们不断进步和提高的动力。同时,如果您还有其他想法或建议,欢迎在评论区与我们分享。再次感谢您的支持,非常期待与您的下一个交流!

相关推荐
杨荧2 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的宠物咖啡馆平台
java·开发语言·jvm·vue.js·spring boot·spring cloud·开源
喜欢打篮球的普通人16 分钟前
rust高级特征
开发语言·后端·rust
Ling_suu32 分钟前
Spring——单元测试
java·spring·单元测试
ModelBulider34 分钟前
十三、注解配置SpringMVC
java·开发语言·数据库·sql·mysql
苹果酱05671 小时前
C语言 char 字符串 - C语言零基础入门教程
java·开发语言·spring boot·mysql·中间件
csucoderlee1 小时前
eclipse mat leak suspects report和 component report的区别
java·ide·eclipse
代码小鑫1 小时前
A032-基于Spring Boot的健康医院门诊在线挂号系统
java·开发语言·spring boot·后端·spring·毕业设计
训山1 小时前
4000字浅谈Java网络编程
java·开发语言·网络
VertexGeek1 小时前
Rust学习(四):作用域、所有权和生命周期:
java·学习·rust
豌豆花下猫1 小时前
REST API 已经 25 岁了:它是如何形成的,将来可能会怎样?
后端·python·ai