再战设计模式之原型模式

Posted bj-xiaodao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了再战设计模式之原型模式相关的知识,希望对你有一定的参考价值。

原型模式(prototype)

这个模式一般在工作中很少用,但是在框架里可能经常有,它是在什么情况下用呢?比如我们创建一个对象,需要10ms,在创建一个对象也需要10ms,这样就很耗时..

举一个很简单的例子.小A在考试,做一份卷子需要一个小时.这时候小A做完啦.小B把小A的卷子.copy过来用了几分钟.做了一些修改,可能比小A的分数还要高.这个就是原型模式

所以我们在创建对象的时候比较耗时.我们在创建一个的时候就可以用原型模式.

  • 浅克隆

  只负责克隆按值传递的数据(比如基本数据类型、String类型),而不复制它所引用的对象,换言之,所有的对其他对象的引用都仍然指向原来的对象。

  • 深克隆

  除了浅度克隆要克隆的值外,还负责克隆引用类型的数据。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深度克隆把要复制的对象所引用的对象都复制了一遍,而这种对被引用到的对象的复制叫做间接复制。

  深度克隆要深入到多少层,是一个不易确定的问题。在决定以深度克隆的方式复制一个对象的时候,必须决定对间接复制的对象时采取浅度克隆还是继续采用深度克隆。因此,在采取深度克隆时,需要决定多深才算深。此外,在深度克隆的过程中,很可能会出现循环引用的问题,必须小心处理。

 浅克隆

public class Sheep implements Cloneable{ //1997 年克隆羊 多利
    private String name;
    private String[] color;

    public String getName() {
        return name;
    }

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

    public String[] getColor() {
        return color;
    }

    public void setColor(String[] color) {
        this.color = color;
    }

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


public class Client1 {

private static Unsafe unsafe;
static final boolean is64bit = true;

static {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 获取对象的内存地址
* @param label
* @param objects
*/
public static void printAddresses(String label, Object... objects) {
System.out.print(label + ": 0x");
long last = 0;
int offset = unsafe.arrayBaseOffset(objects.getClass());
int scale = unsafe.arrayIndexScale(objects.getClass());
switch (scale) {
case 4:
long factor = is64bit ? 8 : 1;
final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor;
System.out.print(Long.toHexString(i1));
last = i1;
for (int i = 1; i < objects.length; i++) {
final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor;
if (i2 > last)
System.out.print(", +" + Long.toHexString(i2 - last));
else
System.out.print(", -" + Long.toHexString( last - i2));
last = i2;
}
break;
case 8:
throw new AssertionError("Not supported");
}
System.out.println();
}

public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep1 = new Sheep();
String[] color = {"黑","白"};
sheep1.setName("多利");
sheep1.setColor(color);
System.out.println("原来 name= "+ sheep1.getName() +" 颜色: " + Arrays.toString( sheep1.getColor()));
Sheep sheep2 = (Sheep) sheep1.clone();
sheep2.setName("克隆??");
String[] color2 = {"黑11","白11"};
sheep2.setColor(color2);

System.out.println("克隆: name= " + sheep2.getName()+" 颜色 = " +Arrays.toString( sheep2.getColor()));
System.out.println(sheep1);
System.out.println(sheep2);
;
//这里看到前克隆之后.内存地址还是和原来指向一个内存地址
printAddresses("color",sheep2.getColor());
printAddresses("color",sheep1.getColor());
}
}

原来 name= 多利 颜色: [黑, 白]
克隆: name= 克隆?? 颜色 = [黑, 白]

结果 引用类型并没有还是原来对象的内存地址,并没有变成新的.

深克隆

public class Sheep implements Cloneable{ //1997 年克隆羊 多利
    private String name;
    private String[] color;

    public String getName() {
        return name;
    }

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

    public String[] getColor() {
    return color;
}

    public void setColor(String[] color) {
        this.color = color;
    }

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

public class Client1 {

    private static Unsafe unsafe;
    static final boolean is64bit = true;

    static {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取对象的内存地址
     * @param label
     * @param objects
     */
    public static void printAddresses(String label, Object... objects) {
        System.out.print(label + ": 0x");
        long last = 0;
        int offset = unsafe.arrayBaseOffset(objects.getClass());
        int scale = unsafe.arrayIndexScale(objects.getClass());
        switch (scale) {
            case 4:
                long factor = is64bit ? 8 : 1;
                final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor;
                System.out.print(Long.toHexString(i1));
                last = i1;
                for (int i = 1; i < objects.length; i++) {
                    final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor;
                    if (i2 > last)
                        System.out.print(", +" + Long.toHexString(i2 - last));
                    else
                        System.out.print(", -" + Long.toHexString( last - i2));
                    last = i2;
                }
                break;
            case 8:
                throw new AssertionError("Not supported");
        }
        System.out.println();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep sheep1 = new Sheep();
        String[] color = {"黑","白"};
        sheep1.setName("多利");
        sheep1.setColor(color);
        System.out.println("原来 name=  "+ sheep1.getName() +" 颜色:   " + Arrays.toString( sheep1.getColor()));
        Sheep sheep2 = (Sheep) sheep1.clone();
        sheep2.setName("克隆??");
        String[] color2 = {"黑11","白11"};
        sheep2.setColor(color2);

        System.out.println("克隆: name= " + sheep2.getName()+" 颜色 =  " +Arrays.toString( sheep2.getColor()));
        System.out.println(sheep1);
        System.out.println(sheep2);
        ;
        //这里看到前克隆之后.内存地址还是和原来指向一个内存地址
        printAddresses("color",sheep2.getColor());
        printAddresses("color",sheep1.getColor());
    }
}


原来 name=  多利 颜色:   [黑, 白]
克隆: name= 克隆?? 颜色 =  [黑11, 白11]
[email protected]
[email protected]
color: 0x76ac297b0, +30
color: 0x76ac28f40, +30

大家看这里的color内存地址也变成新的地址了. 我们可以正常的修改克隆对象的引用了.

利用序列化和反序列实现深克隆

public class Sheep implements Cloneable , Serializable { //1997 年克隆羊 多利
    private String name;
    private String[] color;

    public String getName() {
        return name;
    }

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

    public String[] getColor() {
    return color;
}

    public void setColor(String[] color) {
        this.color = color;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {

        return  super.clone();
    }
}


public class Client3 {

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        Sheep sheep1 = new Sheep();
        String[] color = {"黑","白"};
        sheep1.setName("多利");
        sheep1.setColor(color);
        //序列化和反序列

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream ots = new ObjectOutputStream(bos);

        ots.writeObject(sheep1);
        //sheep1 里面的数据.
        byte[] bytes = bos.toByteArray();


        //反序列化

        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        ObjectInputStream ois = new ObjectInputStream(bis);

        Sheep sheepClone = (Sheep) ois.readObject();
        String[] color1 = {"黑1","白22"};
        sheepClone.setColor(color1);
        System.out.println("原来 name=  "+ sheep1.getName() +" 颜色:   " + Arrays.toString( sheep1.getColor()));
        System.out.println("克隆: name= " + sheepClone.getName()+" 颜色 =  " + Arrays.toString( sheepClone.getColor()));
    }
}

这里我就不获取内存地址了.我们通过修改克隆的对象的应用发现可以修改..就可以了.

 

以上是关于再战设计模式之原型模式的主要内容,如果未能解决你的问题,请参考以下文章

再战设计模式之享元模式

设计模式之原型模式(Prototype)详解及代码示例

创建型设计模式之原型模式

设计模式之原型模式

设计模式之原型

设计模式之原型模式