Java Description Design Mode (05): Prototype Mode

Posted by kritro on Thu, 29 Aug 2019 18:54:55 +0200

Source code for this article: GitHub. Click here || GitEE. Click here

1. Introduction to Prototype Model

1. Basic concepts

The prototype mode belongs to the object creation mode.Indicate the type of all created objects by giving them a prototype object, and then create more objects of the same type by duplicating the prototype object.

2. Pattern Structure

Prototype mode requires the object to implement an interface that "clones" itself so that a new instance can be created by copying an instance object itself.In this way, to create new objects from a prototype instance, you no longer need to care about the type of the instance itself. As long as you implement the method of cloning yourself, you can obtain new objects from this method instead of creating them from new.

3. Code implementation

1), UML Diagram

2) Core Role

This form involves three roles:

1) Client role: The client class makes a request to create an object.

2) Prototype role: This is an abstract role, usually implemented by a Java interface or Java Abstract class.This role gives all the interfaces required for a specific prototype class.

3) Concrete Prototype role: the object being copied.This role needs to implement the interface required by the Abstract prototype role.

3) Implementation based on JDK source code

/**
 * Implement prototype mode based on JDK source mode
 */
public class C01_Property {
    public static void main(String[] args) {
        Product product = new Product("Mechanical keyboard","white",100.00) ;
        Product product1 = (Product) product.clone();
        Product product2 = (Product) product.clone();
        System.out.println(product1);
        System.out.println(product2);
        System.out.println(product1==product2);  // false
    }
}
class Product implements Cloneable {
    private String name ;
    private String color ;
    private Double price ;
    public Product(String name, String color, Double price) {
        this.name = name;
        this.color = color;
        this.price = price;
    }
    @Override
    public String toString() {
        return "Product{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", price=" + price +
                '}';
    }
    @Override
    protected Object clone() {
        Product product = null ;
        try{
            product = (Product)super.clone() ;
        } catch (Exception e){
            e.printStackTrace();
        }
        return product ;
    }
    // Omit GET and SET methods
}

2. Spring Framework Application

1. Profile

<!-- Multiple Cases Bean -->
<bean id="sheep01" class="com.model.design.spring.node05.property.Sheep" scope="prototype" />
<!-- Singleton Bean default: scope="singleton" -->
<bean id="sheep02" class="com.model.design.spring.node05.property.Sheep"/>

2. Test Code Block

@Test
public void test01 (){
    ApplicationContext context01 = new ClassPathXmlApplicationContext(
            "/spring/spring-property.xml");
    // Prototype mode
    Sheep sheep1 = (Sheep)context01.getBean("sheep01") ;
    Sheep sheep2 = (Sheep)context01.getBean("sheep01") ;
    System.out.println(sheep1==sheep2); // false
    // Singleton mode
    Sheep sheep3 = (Sheep)context01.getBean("sheep02") ;
    Sheep sheep4 = (Sheep)context01.getBean("sheep02") ;
    System.out.println(sheep3==sheep4); // true
}

3. Core Source

  • In the class: org.springframework.beans.factory.support.AbstractBeanFactory
  • In method: doGetBean

1) Execution process

if (mbd.isSingleton()) {
    sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {
        public Object getObject() throws BeansException {
            try {
                return AbstractBeanFactory.this.createBean(beanName, mbd, args);
            } catch (BeansException var2) {
                AbstractBeanFactory.this.destroySingleton(beanName);
                throw var2;
            }
        }
    });
    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
    var11 = null;
    Object prototypeInstance;
    try {
        this.beforePrototypeCreation(beanName);
        prototypeInstance = this.createBean(beanName, mbd, args);
    } finally {
        this.afterPrototypeCreation(beanName);
    }
    bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} 

2) Single case and multiple cases

So the default is the singleton mode, and specifying [scope="prototype"] is the prototype mode.

public boolean isSingleton() {
    return "singleton".equals(this.scope) || "".equals(this.scope);
}
public boolean isPrototype() {
    return "prototype".equals(this.scope);
}

3. Shallow and deep copies

1. Shallow copy

1) Data type is a member variable of basic data type and String type. Shallow copy directly transfers the value, that is, duplicates the attribute value to a new object.
2) A data type is a member variable that refers to a data type, such as an array, an object of a class, etc. Shallow copies pass references, that is, just copy the reference value (memory address) of the member variable to a new object.Both object member variables actually point to the same instance.Modifying the properties of one object affects the properties of the other.
3) Shallow copy is implemented using the default clone() method.

2. Deep copy

1) Concept Description

In addition to shallow copies of the values to be copied, it is also responsible for copying the data of the reference type.Variables that refer to other objects will point to new objects that have been copied, instead of the original ones. This copy of the referenced objects is called indirect copy.

2) Source Code Implementation

Serialization for deep cloning

The process of writing objects to a stream is a serialization process; the process of reading objects from a stream is called a Deserialization process.It should be noted that what is written to the stream is a copy of the object, while the original object still exists in the JVM.

Depth cloning of an object in the Java language often starts by making the object implement a Serializable interface, then writing the object (actually just a copy of the object) into a stream (serialization), then reading it back from the stream (deserialization), and then rebuilding the object.

/**
 * Comparison of deep and shallow copies
 */
public class C02_DeepClone {
    public static void main(String[] args) throws Exception {
        Dog dog = new Dog("Tom") ;
        Dog dog1 = (Dog)dog.clone() ;
        Dog dog2 = (Dog)dog.clone() ;
        // dog1: 1639622804;dog2: 1639622804
        System.out.println("dog1: "+dog1.cat.hashCode()+";dog2: "+dog2.cat.hashCode());
        Dog dog3 = (Dog)dog.deepClone() ;
        Dog dog4 = (Dog)dog.deepClone() ;
        // dog3: 1937348256;dog4: 1641808846
        System.out.println("dog3: "+dog3.cat.hashCode()+";dog4: "+dog4.cat.hashCode());
    }
}

class Cat implements Serializable {
    public String name ;
    public Cat (String name){
        this.name = name ;
    }
}
class Dog implements Cloneable,Serializable {
    public String name ;
    public Cat cat ;
    public Dog (String name){
        this.name = name ;
        this.cat = new Cat("Kit") ;
    }
    @Override
    protected Object clone() {
        Dog dog = null ;
        try{
            dog = (Dog)super.clone() ;
        } catch (Exception e){
            e.printStackTrace();
        }
        return dog ;
    }
    public Object deepClone() throws IOException, ClassNotFoundException{
        //Writing objects into streams: serialization
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        //Read Objects from Stream: Deserialization
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }
}

4. Summary of advantages and disadvantages

1. Summary of Advantages

Prototype mode allows dynamic changes to specific implementation types at run time.Prototype mode can either register implementation types that conform to the prototype interface by the client during runtime or dynamically change the specific implementation type. It looks like the interface hasn't changed at all, but it's already running another instance of the class.Because cloning a prototype is like instantiating a class.

2. Summary of shortcomings

The main disadvantage of prototyping is that each class must have a cloning method.Equipping cloning methods requires a general consideration of the functionality of the class, which is not difficult for new classes, but not necessarily easy for existing classes, especially when a class reference does not support serialization of indirect objects, or when it contains a circular structure.

5. Source code address

GitHub Address: Know a smile
https://github.com/cicadasmile/model-arithmetic-parent
 Code Cloud Address: Know a smile
https://gitee.com/cicadasmile/model-arithmetic-parent

Topics: Java Spring github JDK