Java设计模式之原型模式怎么实现

发布时间:2022-09-05 09:44:48 作者:iii
来源:亿速云 阅读:175

Java设计模式之原型模式怎么实现

目录

  1. 引言
  2. 原型模式概述
  3. 原型模式的实现
  4. 原型模式的应用
  5. 原型模式的扩展
  6. 原型模式与其他设计模式的对比
  7. 原型模式的实战案例
  8. 总结
  9. 参考文献

引言

在软件开发中,设计模式是解决常见问题的经典解决方案。原型模式(Prototype Pattern)是创建型设计模式之一,它通过复制现有对象来创建新对象,而不是通过实例化类来创建。这种模式在需要频繁创建相似对象的场景中非常有用,尤其是在对象的创建成本较高时。

本文将详细介绍原型模式的定义、适用场景、实现方式、应用案例以及与其他设计模式的对比。通过本文的学习,读者将能够深入理解原型模式,并能够在实际项目中灵活运用。

原型模式概述

定义

原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制现有对象来创建新对象,而不是通过实例化类来创建。原型模式的核心思想是通过克隆(Clone)来创建对象,从而避免重复的初始化过程。

适用场景

原型模式适用于以下场景:

  1. 对象的创建成本较高:当创建一个对象的成本较高时(例如,对象需要进行复杂的初始化操作),可以通过复制现有对象来避免重复的初始化过程。
  2. 需要频繁创建相似对象:当需要频繁创建相似对象时,可以通过复制现有对象来提高性能。
  3. 对象的类型在运行时确定:当对象的类型在运行时才能确定时,可以通过原型模式来动态创建对象。

优点

  1. 提高性能:通过复制现有对象来创建新对象,避免了重复的初始化过程,从而提高了性能。
  2. 简化对象创建:原型模式简化了对象的创建过程,尤其是在对象的创建成本较高时。
  3. 动态创建对象:原型模式允许在运行时动态创建对象,从而提高了系统的灵活性。

缺点

  1. 深拷贝的实现复杂:在实现深拷贝时,需要递归复制对象的所有引用类型字段,实现起来较为复杂。
  2. 破坏封装性:原型模式需要暴露对象的克隆方法,可能会破坏对象的封装性。

原型模式的实现

浅拷贝

浅拷贝(Shallow Copy)是指复制对象时,只复制对象的基本类型字段和引用类型字段的引用,而不复制引用类型字段所指向的对象。浅拷贝的实现较为简单,但可能会导致对象之间的共享引用类型字段。

在Java中,可以通过实现Cloneable接口并重写clone()方法来实现浅拷贝。以下是一个浅拷贝的示例:

class Address implements Cloneable {
    private String city;

    public Address(String city) {
        this.city = city;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

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

class Person implements Cloneable {
    private String name;
    private Address address;

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

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

public class ShallowCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("New York");
        Person person1 = new Person("John", address);
        Person person2 = (Person) person1.clone();

        System.out.println(person1.getAddress().getCity()); // Output: New York
        System.out.println(person2.getAddress().getCity()); // Output: New York

        person2.getAddress().setCity("Los Angeles");

        System.out.println(person1.getAddress().getCity()); // Output: Los Angeles
        System.out.println(person2.getAddress().getCity()); // Output: Los Angeles
    }
}

在上面的示例中,Person类和Address类都实现了Cloneable接口并重写了clone()方法。通过调用clone()方法,可以创建一个新的Person对象。然而,由于Person类中的address字段是一个引用类型,浅拷贝只复制了address字段的引用,因此person1person2共享同一个Address对象。当修改person2address字段时,person1address字段也会受到影响。

深拷贝

深拷贝(Deep Copy)是指复制对象时,不仅复制对象的基本类型字段和引用类型字段的引用,还复制引用类型字段所指向的对象。深拷贝的实现较为复杂,但可以避免对象之间的共享引用类型字段。

在Java中,可以通过递归调用clone()方法来实现深拷贝。以下是一个深拷贝的示例:

class Address implements Cloneable {
    private String city;

    public Address(String city) {
        this.city = city;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

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

class Person implements Cloneable {
    private String name;
    private Address address;

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone();
        cloned.address = (Address) address.clone();
        return cloned;
    }
}

public class DeepCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("New York");
        Person person1 = new Person("John", address);
        Person person2 = (Person) person1.clone();

        System.out.println(person1.getAddress().getCity()); // Output: New York
        System.out.println(person2.getAddress().getCity()); // Output: New York

        person2.getAddress().setCity("Los Angeles");

        System.out.println(person1.getAddress().getCity()); // Output: New York
        System.out.println(person2.getAddress().getCity()); // Output: Los Angeles
    }
}

在上面的示例中,Person类在重写clone()方法时,不仅调用了super.clone()方法,还递归调用了address字段的clone()方法。这样,person1person2address字段指向不同的Address对象,因此修改person2address字段不会影响person1address字段。

原型模式的应用

Java中的Cloneable接口

在Java中,Cloneable接口是一个标记接口(Marker Interface),它没有任何方法。实现Cloneable接口的类可以通过重写clone()方法来实现对象的克隆。clone()方法是Object类的一个受保护方法,因此需要在子类中重写并将其访问修饰符改为public

以下是一个简单的Cloneable接口的实现示例:

class Person implements Cloneable {
    private String name;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class CloneableExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("John");
        Person person2 = (Person) person1.clone();

        System.out.println(person1.getName()); // Output: John
        System.out.println(person2.getName()); // Output: John

        person2.setName("Jane");

        System.out.println(person1.getName()); // Output: John
        System.out.println(person2.getName()); // Output: Jane
    }
}

在上面的示例中,Person类实现了Cloneable接口并重写了clone()方法。通过调用clone()方法,可以创建一个新的Person对象。由于Person类中的name字段是一个基本类型字段,因此person1person2name字段是独立的,修改person2name字段不会影响person1name字段。

原型模式在Spring中的应用

在Spring框架中,原型模式被广泛应用于Bean的创建。Spring中的Bean默认是单例(Singleton)的,即每个Bean在Spring容器中只有一个实例。然而,在某些情况下,可能需要为每个请求创建一个新的Bean实例,这时可以使用原型模式。

在Spring中,可以通过在Bean定义中设置scope="prototype"来将Bean配置为原型模式。以下是一个Spring中原型模式的示例:

<bean id="person" class="com.example.Person" scope="prototype">
    <property name="name" value="John"/>
</bean>

在上面的示例中,person Bean被配置为原型模式。每次从Spring容器中获取person Bean时,都会创建一个新的Person对象。

以下是一个Spring中原型模式的Java代码示例:

class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class SpringPrototypeExample {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        Person person1 = (Person) context.getBean("person");
        Person person2 = (Person) context.getBean("person");

        System.out.println(person1.getName()); // Output: John
        System.out.println(person2.getName()); // Output: John

        person2.setName("Jane");

        System.out.println(person1.getName()); // Output: John
        System.out.println(person2.getName()); // Output: Jane
    }
}

在上面的示例中,person1person2是两个不同的Person对象,因此修改person2name字段不会影响person1name字段。

原型模式的扩展

原型管理器

原型管理器(Prototype Manager)是一种管理原型对象的工具,它允许在运行时动态注册和获取原型对象。原型管理器通常用于管理多个原型对象,并根据需要动态创建新对象。

以下是一个原型管理器的示例:

import java.util.HashMap;
import java.util.Map;

interface Prototype extends Cloneable {
    Prototype clone() throws CloneNotSupportedException;
}

class ConcretePrototypeA implements Prototype {
    private String name;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Prototype clone() throws CloneNotSupportedException {
        return (Prototype) super.clone();
    }
}

class ConcretePrototypeB implements Prototype {
    private int id;

    public ConcretePrototypeB(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

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

    @Override
    public Prototype clone() throws CloneNotSupportedException {
        return (Prototype) super.clone();
    }
}

class PrototypeManager {
    private Map<String, Prototype> prototypes = new HashMap<>();

    public void registerPrototype(String key, Prototype prototype) {
        prototypes.put(key, prototype);
    }

    public Prototype getPrototype(String key) throws CloneNotSupportedException {
        Prototype prototype = prototypes.get(key);
        if (prototype != null) {
            return prototype.clone();
        }
        return null;
    }
}

public class PrototypeManagerExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        PrototypeManager manager = new PrototypeManager();

        manager.registerPrototype("A", new ConcretePrototypeA("Prototype A"));
        manager.registerPrototype("B", new ConcretePrototypeB(1));

        Prototype prototypeA1 = manager.getPrototype("A");
        Prototype prototypeA2 = manager.getPrototype("A");
        Prototype prototypeB1 = manager.getPrototype("B");
        Prototype prototypeB2 = manager.getPrototype("B");

        System.out.println(((ConcretePrototypeA) prototypeA1).getName()); // Output: Prototype A
        System.out.println(((ConcretePrototypeA) prototypeA2).getName()); // Output: Prototype A
        System.out.println(((ConcretePrototypeB) prototypeB1).getId()); // Output: 1
        System.out.println(((ConcretePrototypeB) prototypeB2).getId()); // Output: 1

        ((ConcretePrototypeA) prototypeA2).setName("New Prototype A");
        ((ConcretePrototypeB) prototypeB2).setId(2);

        System.out.println(((ConcretePrototypeA) prototypeA1).getName()); // Output: Prototype A
        System.out.println(((ConcretePrototypeA) prototypeA2).getName()); // Output: New Prototype A
        System.out.println(((ConcretePrototypeB) prototypeB1).getId()); // Output: 1
        System.out.println(((ConcretePrototypeB) prototypeB2).getId()); // Output: 2
    }
}

在上面的示例中,PrototypeManager类用于管理多个原型对象。通过调用registerPrototype()方法,可以将原型对象注册到管理器中。通过调用getPrototype()方法,可以从管理器中获取原型对象的克隆。

原型模式的变体

原型模式有多种变体,以下是几种常见的变体:

  1. 懒加载原型模式:在懒加载原型模式中,原型对象在第一次使用时才被创建。这种模式适用于原型对象的创建成本较高且不一定会被使用的场景。
  2. 多态原型模式:在多态原型模式中,原型对象可以是不同类型的对象。这种模式适用于需要动态创建不同类型对象的场景。
  3. 组合原型模式:在组合原型模式中,原型对象可以包含其他原型对象。这种模式适用于需要创建复杂对象的场景。

原型模式与其他设计模式的对比

与工厂模式的对比

工厂模式(Factory Pattern)和原型模式都是创建型设计模式,但它们的目的和实现方式有所不同。

与单例模式的对比

单例模式(Singleton Pattern)和原型模式都是创建型设计模式,但它们的目的和实现方式有所不同。

原型模式的实战案例

案例1:游戏中的角色创建

在游戏中,角色的创建通常是一个复杂的过程,涉及到多个属性的初始化。如果每次创建角色时都进行完整的初始化操作,可能会导致性能问题。这时可以使用原型模式来复制现有角色对象,从而避免重复的初始化过程。

以下是一个游戏角色创建的示例:

”`java class GameCharacter implements Cloneable { private String name; private int level; private String weapon;

public GameCharacter(String name, int level, String weapon) {
    this.name = name;
    this.level = level;
    this.weapon = weapon;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getLevel() {
    return level;
}

public void setLevel(int level) {
    this.level = level;
}

public String getWeapon() {
    return weapon;
}

public void setWeapon(String weapon) {
    this.weapon = weapon;
}

@Override
public GameCharacter clone() throws CloneNotSupportedException {
    return (GameCharacter) super.clone();
}

}

public class GameCharacterExample { public static void main(String[] args) throws CloneNotSupportedException { GameCharacter character1 = new GameCharacter(“Warrior”, 1, “Sword”); GameCharacter character2 = character1.clone();

    System.out.println(character1.getName() + " " + character1.getLevel() + " " + character1.getWeapon()); // Output: Warrior 1 Sword
    System.out.println(character2.getName() + " " + character2.getLevel() + " " + character2.getWeapon()); // Output: Warrior 1 Sword

    character2.setName("Mage");
    character2.setLevel(5);
    character2.setWeapon("Staff");

    System.out.println(character1.getName() + " " + character1.getLevel() + " " + character1.getWeapon()); // Output: Warrior 1 Sword
    System.out.println(character2.getName() + " " + character2.getLevel() + " " + character2.getWeapon()); // Output: Mage 
推荐阅读:
  1. php设计模式之——原型模式
  2. java设计模式之委派模式如何实现

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:Django ORM多表查询怎么实现

下一篇:Python标准库中的logging怎么使用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》