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

来源:互联网 发布:暂七师军乐队 知乎 编辑:程序博客网 时间:2024/04/20 15:00

原型模式(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 :图片103-31 16:58:16.035 27552-27552/? E/zsf: image name :图片203-31 16:58:16.035 27552-27552/? E/zsf: image name :图片303-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 :图片103-31 16:58:16.035 27552-27552/? E/zsf: image name :图片203-31 16:58:16.035 27552-27552/? E/zsf: image name :图片303-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 :图片103-31 16:58:16.035 27552-27552/? E/zsf: image name :图片203-31 16:58:16.035 27552-27552/? E/zsf: image name :图片303-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 :图片103-31 16:58:16.036 27552-27552/? E/zsf: image name :图片203-31 16:58:16.036 27552-27552/? E/zsf: image name :图片303-31 16:58:16.036 27552-27552/? E/zsf: ------word Content End------

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

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


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

/*** 克隆对象*/@Overrideprotected 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
原创粉丝点击