您的当前位置:首页正文

java设计模式总结四:原型模式

2024-11-26 来源:个人技术集锦
原型模式定义
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。它属于创建型模式。原型模式主要用于实现对象的复制
原型模式简单的说就是:通过一个原型对象来表明要创建的对象类型,然后通过复制这个原型对象的方法来创建同类型的对象


原型模式的使用场景
假设对于一个产品的再生产,每次都生产同样的产品,可以使用如下代码实现:
//产品类
public class Product{
    private int id;
    private double price;
    //omit set and get method
    ...
}

//客户端生产代码
public class Client{
    public static void main(String[] args){
        Product product1 = new Product();
        product1.setId(1);
        product1.setPrice(100);
        Product product2 = product1;
        //无休止的赋值product1来生产完全相同的产品对象            
    }
}
可是这个时候突然新的产品价格上调了,比如为150了,那么就需要对后续的产品进行略微改动:
//客户端生产代码
public class Client{
    public static void main(String[] args){
        Product product1 = new Product();
        product1.setId(1);
        product1.setPrice(100);
        Product product2 = product1;
        product2.setPrice(150);
        //无休止的赋值product2来生产完全相同的产品对象            
    }
}
然而,通过上面的代码真的可以实现吗?我们进行代码测试:
//客户端生产代码
public class Client{
    public static void main(String[] args){
        Product product1 = new Product();
        product1.setId(1);
        product1.setPrice(100);
        Product product2 = product1;
        product2.setPrice(150);
        System.out.println("product1.Price->"+product1.getPrice());     
    }
}
最终我们发现输出的值不是100,而是150,这是为什么呢?因为java中的对象是地址传递的,product2和product1指向同一个地址,从而product2的改变对product1以及所有指向该地址的引用都生效。
所以这个时候就需要用到原型模式来创建一个原型对象的副本了


原型模式的实现1
在java中提供了原型模式的实现接口Clonable,需要实现原型模式的产品类通过实现该接口并且重写clone方法来生成原型对象的副本,上面的实现代码设计成原型模式如下:
//产品类
public class Product implements Clonable{
    ...
    @Override
    public Object clone(){
        Object obj = null;
        try{
            obj = super.clone();
        }
        catch(ClassNotSupportedException e){
            e.printStackTrace();
        }
        return obj;     
    }
}

//客户端生产产品
//客户端生产代码
public class Client{
    public static void main(String[] args){
        Product product1 = new Product();
        product1.setId(1);
        product1.setPrice(100);
        Product product2 = product1.clone();
        product2.setPrice(150);
        System.out.println("product1.price->"+product1.getPrice());
        System.out.println("product2.price->"+product2.getPrice());
        //无休止的赋值product2来生产完全相同的产品对象            
    }
}
上面客户端测试代码输出结果为100和150,从而实现了原型模式
其核心主要还是通过获得的原型对象来克隆一个与该对象类型相同的新对象,我们知道所有的类都继承了顶级父类java.lang.Object,而在该类中有一个clone方法可以克隆当前对象并返回一个新的对象,就相当于:
newobj = obj.clone();
//等同于如下代码
newobj = new Object();
newobj.setId(obj.getId());
newobj.setPrice(obj.getPrice());
因此对于java提供的原型模式的实现,总结来说需要满足以下两个条件:
1.实现了Clonable接口
2.重写了clone方法


原型模式的实现2
前面介绍的是通过java提供的Clonable接口来实现的,那么如果不适用java自带的话该如何实现了,其实原理和java提供的接口一样,就是自定义一个Clonable接口,并通过创建新对象并且将原型对象的值更新给新对象从而实现clone,实现代码如下:
//定义一个克隆接口类
public interface Clonable{
    public Object clone();
}

//产品类
public class Product implements Clonable{
    ...
    @Override
    public Object clone(){
        Object obj = new Product();
        obj.setId(this.getId());
        obj.setPrice(this.setPrice());
        return obj;     
    }
}

//客户端测试类代码
//客户端生产代码
public class Client{
    public static void main(String[] args){
        Product product1 = new Product();
        product1.setId(1);
        product1.setPrice(100);
        Product product2 = product1.clone();
        //无休止的赋值来生产完全相同的产品对象            
    }
}
两个实现的方式的本质都是一样的,就是创建新的对象,然后将原型对象一系列属性值都赋值给该新对象,从而实现原型模式


引用的陷阱
这里值得提出来的一个问题是:如果进行原型模式设计的类中包含引用类型的属性,重写clone时就需要注意该属性值也需要重新new,否则也会修改对应的属性,因为引用类型的值都是通过地址进行传递的(除了String,在java中它是不变字符串)
显示全文