Java设计模式笔记之原型模式

原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。(引用自——《大话设计模式》)


原型类:

public abstract class Prototype {

    private String id;

    public Prototype(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    public abstract Prototype clone();

}
具体类:

public class ConcretePrototypeOne extends Prototype {

    public ConcretePrototypeOne(String id) {
        super(id);
    }

    @Override
    public Prototype clone() {
        //创建当前对象的浅表副本
        return this.clone();
    }
}

客户端:

public class ResumeTestActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ConcretePrototypeOne p1 = new ConcretePrototypeOne("I");
        ConcretePrototypeOne c1 = (ConcretePrototypeOne) p1.clone();//克隆对象
        L.e("复制的:" + c1.getId());
    }
}

下面是一个具体的列子:

/**
 * Created by zsf 
 * 原型模式
 * WordDocument,文档类型,扮演的是ConcretePrototype角色,而cloneable是代表prototype角色
 * 模拟了Word文档中的图片和文字元素,
 */

public class WordDocument implements Cloneable{

    //文本
    private String mText;
    //图片名列表
    private ArrayList<String> mImages = new ArrayList<>();

    public WordDocument(){
        L.e("--------------WordDocument构造函数");
    }

    /**
     * 实现对象克隆,该方法不是Cloneable接口中的,而是Object中的方法。Cloneable也是一个标识接口,表明这个类的
     * 对象是可以拷贝的。没有实现Cloneable接口却调用clone()方法会抛出异常
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected WordDocument clone() throws CloneNotSupportedException {
        WordDocument doc = (WordDocument) super.clone();
        doc.mText = this.mText;
        doc.mImages = this.mImages;
        return doc;

    }

    public String getText(){
        return mText;
    }

    public void setText(String mText){
        this.mText = mText;
    }

    public List<String> getImages(){
        return mImages;
    }
    public void addImage(String img){
        this.mImages.add(img);
    }

    /**
     * 打印文档内容
     */
    public void showDoucment(){
        L.e("----------word Content Start------");
        L.e("Text:" + mText);
        L.e("Images List:");
        for (String imgName : mImages){
            L.e("image name :" + imgName);
        }
        L.e("------word Content End------");
    }

}
客户端代码:
/**
 * Created by zsf
 *
 * 注意!!通过clone拷贝对象时,并不会执行构造函数
 */

public class WordDocumentTestActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //1.构建文档对象
        WordDocument document = new WordDocument();
        //2.编辑文档,添加图片等
        document.setText("这是一篇文档");
        document.addImage("图片1");
        document.addImage("图片2");
        document.addImage("图片3");
        document.showDoucment();

        try {
            //以原始文档为原型,拷贝一份副本

            WordDocument copyDocument = document.clone();
            copyDocument.showDoucment();
            //修改文档副本,不会影响原始文档
            copyDocument.setText("这是修改过的拷贝文档");
            copyDocument.showDoucment();

            document.showDoucment();

        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }


    }

}
我们发现上面的例子并没有Protototype抽象类,因为我们实现了Cloneable接口,并且重写了里面的clone()方法。


打印的Log

03-31 16:58:16.034 27552-27552/? E/zsf: --------------WordDocument构造函数
03-31 16:58:16.034 27552-27552/? E/zsf: ----------word Content Start------
03-31 16:58:16.035 27552-27552/? E/zsf: Text:这是一篇文档
03-31 16:58:16.035 27552-27552/? E/zsf: Images List:
03-31 16:58:16.035 27552-27552/? E/zsf: image name :图片1
03-31 16:58:16.035 27552-27552/? E/zsf: image name :图片2
03-31 16:58:16.035 27552-27552/? E/zsf: image name :图片3
03-31 16:58:16.035 27552-27552/? E/zsf: ------word Content End------
03-31 16:58:16.035 27552-27552/? E/zsf: ----------word Content Start------
03-31 16:58:16.035 27552-27552/? E/zsf: Text:这是一篇文档
03-31 16:58:16.035 27552-27552/? E/zsf: Images List:
03-31 16:58:16.035 27552-27552/? E/zsf: image name :图片1
03-31 16:58:16.035 27552-27552/? E/zsf: image name :图片2
03-31 16:58:16.035 27552-27552/? E/zsf: image name :图片3
03-31 16:58:16.035 27552-27552/? E/zsf: ------word Content End------
03-31 16:58:16.035 27552-27552/? E/zsf: ----------word Content Start------
03-31 16:58:16.035 27552-27552/? E/zsf: Text:这是修改过的拷贝文档
03-31 16:58:16.035 27552-27552/? E/zsf: Images List:
03-31 16:58:16.035 27552-27552/? E/zsf: image name :图片1
03-31 16:58:16.035 27552-27552/? E/zsf: image name :图片2
03-31 16:58:16.035 27552-27552/? E/zsf: image name :图片3
03-31 16:58:16.035 27552-27552/? E/zsf: ------word Content End------
03-31 16:58:16.036 27552-27552/? E/zsf: ----------word Content Start------
03-31 16:58:16.036 27552-27552/? E/zsf: Text:这是一篇文档
03-31 16:58:16.036 27552-27552/? E/zsf: Images List:
03-31 16:58:16.036 27552-27552/? E/zsf: image name :图片1
03-31 16:58:16.036 27552-27552/? E/zsf: image name :图片2
03-31 16:58:16.036 27552-27552/? E/zsf: image name :图片3
03-31 16:58:16.036 27552-27552/? E/zsf: ------word Content End------

谈及原型模式,不得不说的一个知识点就是浅拷贝和深拷贝

上面原型模式的实现只是一个浅拷贝,又称影子拷贝。原理就是副本文档的字段引用原始文档的字段。
我们知道A引用B就是两个对象指向同一个地址,当修改A时B也会改变,B修改时A同样会改变。


如何解决上面的问题就是要使用深拷贝。
深拷贝,即在拷贝对象的同时,对于引用型的字段也要采用拷贝的形式,而不是单纯引用形式。clone方法修改如下:

/**
* 克隆对象
*/
@Override
protected WordDocument clone(){
	try{
		WordDocument doc = (WordDocument)super.clone();
		doc.mText = this.mText;
		//对mImages对象也调用clone()函数,进行深拷贝
		doc.mImages = (ArrayList<String>)this.mImages.clone();
		return doc;
	}catch(Exception e){
		
	}
	
	return null;
}

上面中doc.mImages指向了this.mImages的一份拷贝,而不是this.mImages本身,这样在copyDocument中添加图片不会影响原Document。

原型模式是简单的一个模式,核心问题就是对原始对象进行拷贝,在使用该模式时需要注意的就是深浅拷贝的问题,建议直接使用深拷贝。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值