目錄
java23種設計模式—— 一、設計模式介紹
java23種設計模式—— 二、單例模式
java23種設計模式——三、工廠模式
java23種設計模式——四、原型模式
java23種設計模式——五、建造者模式
java23種設計模式——六、適配器模式
java23種設計模式——七、橋接模式
java23種設計模式——八、組合模式
java23種設計模式——四、原型模式
這種模式是實現了一個原型接口,該接口用於創建當前對象的克隆。當直接創建對象的代價比較大時,則采用這種模式。例如,一個對象需要在一個高代價的數據庫操作之后被創建。我們可以緩存該對象,在下一個請求時返回它的克隆,在需要的時候更新數據庫,以此來減少數據庫調用。
舉個例子,就是當我們需要給電腦安裝win10系統時需要去官網上下載win10系統的安裝包。而安裝包的大小都是很耗時的,還需要另一台電腦來操作。如果我們下載了一個安裝包放在我們的u盤里,之后需要安裝win10時是不是就省去了中間尋找,下載等時間呢
原型模式的克隆分為淺克隆和深克隆,Java 中的 Object 類提供了淺克隆的 clone() 方法,具體原型類只要實現 Cloneable 接口就可實現對象的淺克隆,這里的 Cloneable 接口就是抽象原型類。其代碼如下
淺克隆
新建一個實體類Sheep實現Cloneable 接口,重寫clone()方法
/**
* @author codermy
* @createTime 2020/5/14
*/
public class Sheep implements Cloneable{
private String name;
private int age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Sheep(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
//克隆該實例,使用默認的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep =null;
sheep = (Sheep)super.clone();
return sheep;
}
}
測試
/**
* @author codermy
* @createTime 2020/5/14
*/
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep = new Sheep("tom",1,"male");
Sheep sheep1 = (Sheep)sheep.clone();
System.out.println(sheep.hashCode());
System.out.println(sheep);
System.out.println(sheep1.hashCode());
System.out.println(sheep1);
sheep1.setAge(2);
System.out.println(sheep1);
System.out.println(sheep);
}
}
輸出
1163157884
Sheep{name='tom', age=1, sex='male'}
1956725890
Sheep{name='tom', age=1, sex='male'}
Sheep{name='tom', age=2, sex='male'}
Sheep{name='tom', age=1, sex='male'}
在淺克隆中,被復制對象的所有普通成員變量都具有與原來對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。也就是說,淺克隆僅僅復制所考慮的對象,不會復制它所引用的成員對象。
我們先新建一個Pearson類,作為對象屬性
/**
* @author codermy
* @createTime 2020/7/24
*/
public class Person implements Cloneable{
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(){
}
public Person(String name){
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
我們先給Sheep實體類種添加一個對象屬性
/**
* @author codermy
* @createTime 2020/6/16
*/
public class Sheep implements Cloneable {
private String name;
private int age;
private String sex;
public Person owner;//對象引用
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Person getOwner() {
return owner;
}
public void setOwner(Person owner) {
this.owner = owner;
}
public Sheep(String name, int age, String sex, Person owner) {
this.name = name;
this.age = age;
this.sex = sex;
this.owner = owner;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", owner=" + owner +
'}';
}
//克隆該實例,使用默認的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep =null;
sheep = (Sheep)super.clone();
return sheep;
}
}
測試類中測試
/**
* @author codermy
* @createTime 2020/6/16
*/
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Person owner = new Person("馬雲");
Sheep sheep = new Sheep("tom",1,"male", owner);//新建sheep類
Sheep sheep1 = (Sheep)sheep.clone();//克隆該類
System.out.println(sheep.hashCode() + " " + sheep.owner.hashCode());
System.out.println(sheep + " "+ sheep.owner);
System.out.println(sheep1.hashCode()+ " " + sheep1.owner.hashCode());
System.out.println(sheep1 + " " + sheep1.owner);
sheep1.owner.setName("馬化騰");
System.out.println(sheep.owner);
System.out.println(sheep1.owner);
}
}
輸出
1163157884 1956725890
Sheep{name='tom', age=1, sex='male', owner=Person{name='馬雲'}} Person{name='馬雲'}
356573597 1956725890
Sheep{name='tom', age=1, sex='male', owner=Person{name='馬雲'}} Person{name='馬雲'}
Person{name='馬化騰'}
Person{name='馬化騰'}
我們可以看出淺克隆時對象的引用僅僅是指向了原空間,而並沒有復制對象。
深克隆
在深克隆中,對值類型的成員變量進行值的復制,對引用類型的成員變量也進行引用對象的復制。
自定義clone過程實現深克隆
將上面Sheep類中的clone方法改寫
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep =null;
sheep = (Sheep)super.clone();
sheep.owner = (Person) sheep.owner.clone();//引用對象的克隆方法
return sheep;
}
測試類測試
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Person owner = new Person("馬雲");
Sheep sheep = new Sheep("tom",1,"male", owner);
Sheep sheep1 = (Sheep)sheep.clone();
System.out.println(sheep.hashCode() + " " + sheep.owner.hashCode());
System.out.println(sheep + " "+ sheep.owner);
System.out.println(sheep1.hashCode()+ " " + sheep1.owner.hashCode());
System.out.println(sheep1 + " " + sheep1.owner);
sheep1.owner.setName("馬化騰");
System.out.println(sheep.owner);
System.out.println(sheep1.owner);
}
}
輸出
1163157884 1956725890
Sheep{name='tom', age=1, sex='male', owner=Person{name='馬雲'}} Person{name='馬雲'}
356573597 1735600054
Sheep{name='tom', age=1, sex='male', owner=Person{name='馬雲'}} Person{name='馬雲'}
Person{name='馬雲'}
Person{name='馬化騰'}
這時候我們已經實現了深克隆,但是總覺得有點“淺淺克隆”的意思,如果person類中還有對象引用那不就是。。
禁止套娃
序列化實現深克隆
兩個實體類實現序列化接口
Person類
public class Person implements Serializable {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
public Person(String name){
this.name = name;
}
}
Sheep類
/**
* @author codermy
* @createTime 2020/6/16
*/
public class Sheep implements Serializable {
private String name;
private int age;
private String sex;
public Person owner;//對象引用
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Person getOwner() {
return owner;
}
public void setOwner(Person owner) {
this.owner = owner;
}
public Sheep() {
}
public Sheep(String name, int age, String sex, Person owner) {
this.name = name;
this.age = age;
this.sex = sex;
this.owner = owner;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", owner=" + owner +
'}';
}
}
實現
**
* @author codermy
* @createTime 2020/7/24
*/
public class Client {
public static void main(String[] args) throws Exception {
Person owner = new Person("馬雲");
Sheep sheep = new Sheep("tom",1,"male", owner);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(sheep);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
Sheep sheep1 =(Sheep) ois.readObject();
bos.flush();oos.flush();
bos.close();oos.close();
ois.close();
System.out.println("Sheep: " + sheep);
System.out.println("Sheep1: " + sheep1);
System.out.println("================================");
System.out.println("Sheep: " + sheep.hashCode() + "++++++++++" + sheep.owner.hashCode());
System.out.println("Sheep1: " + sheep1.hashCode() + "++++++++++" + sheep1.owner.hashCode());
System.out.println("================================");
sheep1.owner.setName("馬化騰");
System.out.println("Sheep: " + sheep.owner);
System.out.println("Sheep1: " + sheep1.owner);
}
}
輸出
1163157884 1956725890
Sheep{name='tom', age=1, sex='male', owner=Person{name='馬雲'}} Person{name='馬雲'}
356573597 1735600054
Sheep{name='tom', age=1, sex='male', owner=Person{name='馬雲'}} Person{name='馬雲'}
Person{name='馬雲'}
Person{name='馬化騰'}
原型模式的優缺點
優點:原型模式是在內存中二進制流的拷貝,要比new一個對象的性能要好,特別是需要產生大量對象時。
缺點:直接在內存中拷貝,構造函數是不會執行的。