创建型模式 - 原型模式(拷贝对象)

原型模式(Prototype Pattern)

意图

指定创建对象的种类,并且通过拷贝创建新的对象。

原型模式复制的克隆对象≠原对象,内存地址段不同,但是属性状态相同。

角色

角色名称 中文名称 作用描述
Client 客户类 让一个原型克隆自身从而获得新的对象
Prototype 原型接口 声明克隆的接口
ConcretePrototype 具体原型类 实现声明的克隆接口

特点

  • 优点
  1. 当要克隆的对象比较复杂时,原型模式的克隆方法能简化对象创建过程,提高创建对象效率;
  2. 克隆对象保持了原对象的所有属性状态;
  3. 原型提供了简化的创建结构;
  • 缺点
  1. 深克隆时,要为每一个原型的属性对象都创建克隆方法,可能需要修改原有类实现,不符合对扩展开放、对修改关闭的“开闭”原则;

适用场景

  1. 创建对象的过程比较复杂,可以利用已有对象进行复制,如需要深克隆;
  2. 需要保持对象状态,或者状态变化较少,可以利用原型克隆对象。

深克隆&浅克隆

克隆:复制一个原有对象,产生一个新对象。[浅克隆,深克隆统称]
浅克隆:会复制所有属性值,如果属性是对象地址/引用,不会复制对象本身,而仅仅是复制对象地址/引用;[仅复制一次对象]
深克隆:不仅会复制所以属性值,而且会复制属性所代表对象本身,如果还包含子对象,也会进行迭代复制;[迭代复制对象]

通用类图

示例

现以一个舰船的小游戏为例:敌舰EnemyShip包含name, damage, size, position 4个共有属性。

示例代码

  1. 创建要克隆的原型EnemyShip接口/抽象类, 以及属性对象Position, Size对应类
    EnemyShip抽象类,在clone方法复制position和size对象属性目的是为了进行深克隆。如若是浅克隆可以不用创建新属性对象。
    EnemyShip类
// EnemyShip.java
public abstract class EnemyShip {
    protected String name;
    protected float damage;
    protected Size size;
    protected Position position;
     
    public abstract EnemyShip clone();
     
    /**
     * 打印各属性信息
     * 如果具体实现类有新添的属性, 需要重写该方法
     */
    public void display() {
        System.out.println(this.getClass().toString() + ": [" );
        System.out.println("Name: " + getName());
        System.out.println("Damage: " + getDamage());
        System.out.println("Size: (" + getSize().getWidth() + " , " + getSize().getHeight() + ")");
        System.out.println("Position: " + getPosition().getX() + " , " + getPosition().getY() + ")");
        System.out.println("]");
    }
     
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public float getDamage() {
        return damage;
    }
 
    public void setDamage(float damage) {
        this.damage = damage;
    }
 
    public Size getSize() {
        return size;
    }
 
    public void setSize(Size size) {
        this.size = size;
    }
 
    public Position getPosition() {
        return position;
    }
 
    public void setPosition(Position position) {
        this.position = position;
    }
}

Position类

// Position.java
public class Position {
    private int x;
    private int y;
     
    public Position(int x, int y) {
        this.x = x;
        this.y = y;
    }
     
    public Position(Position p) {
        this.x = p.x;
        this.y = p.y;
    }
 
    public int getX() {
        return x;
    }
 
    public void setX(int x) {
        this.x = x;
    }
 
    public int getY() {
        return y;
    }
 
    public void setY(int y) {
        this.y = y;
    }
}

Size类

// Size.java
public class Size {
    private int width;
    private int height;
     
    public Size(int width, int height) {
        this.width = width;
        this.height = height;
    }
     
    public Size(Size s) {
        this.width = s.width;
        this.height = s.height;
    }
     
    public int getWidth() {
        return width;
    }
    public void setWidth(int width) {
        this.width = width;
    }
    public int getHeight() {
        return height;
    }
    public void setHeight(int height) {
        this.height = height;
    }
}
  1. 创建具体要实现克隆的原型类UFO, Rocket, Ultimate EnemyShip
    原型实现类UFOEnemyShip
// UFOEnemyShip
public class UFOEnemyShip  extends EnemyShip{
 
    @Override
    public EnemyShip clone() {
        EnemyShip clone = new UFOEnemyShip();
         
        if(clone != null){
 
            Position p = new Position(this.getPosition());
            clone.setPosition(p);
 
            Size s = new Size(this.getSize());
            clone.setSize(s);
        }
         
        return clone;
    }
/* 
    public void display() {
        System.out.println(this.getClass().toString() + ": [" );
        System.out.println("Name: " + getName());
        System.out.println("Damage: " + getDamage());
        System.out.println("Size: (" + getSize().getWidth() + " , " + getSize().getHeight() + ")");
        System.out.println("Position: " + getPosition().getX() + " , " + getPosition().getY() + ")");
    }*/
}

原型实现类RocketEnemyShip

// UFOEnemyShip
public class UFOEnemyShip  extends EnemyShip{
 
    @Override
    public EnemyShip clone() {
        EnemyShip clone = new UFOEnemyShip();
         
        if(clone != null){
 
            Position p = new Position(this.getPosition());
            clone.setPosition(p);
 
            Size s = new Size(this.getSize());
            clone.setSize(s);
        }
         
        return clone;
    }
/* 
    public void display() {
        System.out.println(this.getClass().toString() + ": [" );
        System.out.println("Name: " + getName());
        System.out.println("Damage: " + getDamage());
        System.out.println("Size: (" + getSize().getWidth() + " , " + getSize().getHeight() + ")");
        System.out.println("Position: " + getPosition().getX() + " , " + getPosition().getY() + ")");
    }*/
}

原型实现类RocketEnemyShip

// RocketEnemyShip.java
public class RocketEnemyShip extends EnemyShip {
     
    @Override
    public EnemyShip clone() {
        EnemyShip clone = new RocketEnemyShip();
         
        if(clone != null){
            Position p = new Position(this.getPosition());
            clone.setPosition(p);
 
            Size s = new Size(this.getSize());
            clone.setSize(s);
        }
        return clone;
    }
}

原型实现类UltimateEnemyShip

// UltimateEnemyShip.java
public class UltimateEnemyShip extends EnemyShip {
 
    @Override
    public EnemyShip clone() {
        EnemyShip clone = new UltimateEnemyShip();
         
        if(clone != null){
            Position p = new Position(this.getPosition());
            clone.setPosition(p);
 
            Size s = new Size(this.getSize());
            clone.setSize(s);
        }
        return clone;
    }
}
  1. 创建客户类,使用EnemyShip UFO类对象进行克隆Rocket, Ultimiate
    客户端类Client
// Client.java
public class Client {
    public static void main(String[] args) {
        // 新建ufo
        EnemyShip ufo = new UFOEnemyShip();
        ufo.setName("UFO");
        ufo.setDamage(15);
        ufo.setPosition(new Position(0, 0));
        ufo.setSize(new Size(5,5));
         
        // 利用ufo克隆rocket
        EnemyShip rocket = ufo.clone();
        rocket.setName("Rocket");
        rocket.setDamage(20);
        rocket.setPosition(new Position(10, 12));
        rocket.setSize(new Size(15, 15));
         
        // 利用ufo克隆ultimate
        EnemyShip ultimate = ufo.clone();
        ultimate.setName("Ultimate");
        ultimate.setDamage(100);
        ultimate.setPosition(new Position(20, 16));
        ultimate.setSize(new Size(30, 30));
         
        // 显示创建对象信息
        ufo.display();
        rocket.display();
        ultimate.display();
    }
}

运行结果

Console输出结果

class DesignPattern.UFOEnemyShip: [
Name: UFO
Damage: 15.0
Size: (5 , 5)
Position: 0 , 0)
]
class DesignPattern.UFOEnemyShip: [
Name: Rocket
Damage: 20.0
Size: (15 , 15)
Position: 10 , 12)
]
class DesignPattern.UFOEnemyShip: [
Name: Ultimate
Damage: 100.0
Size: (30 , 30)
Position: 20 , 16)
]

参考

  1. 设计模式:原型模式, 博客园
  2. Java clone深拷贝、浅拷贝, CSDN
  3. Cloneable接口和Object的clone()方法, 博客园
posted @ 2018-10-17 23:51  明明1109  阅读(297)  评论(0编辑  收藏  举报