日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

设计模式【5】-- 原型模式

發布時間:2024/3/13 asp.net 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 设计模式【5】-- 原型模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

開局一張圖,剩下全靠寫…

設計模式文章集合:http://aphysia.cn/categories/designpattern

前言

接觸過 Spring 或者 Springboot 的同學或許都了解, Bean 默認是單例的,也就是全局共用同一個對象,不會因為請求不同,使用不同的對象,這里我們不會討論單例,前面已經討論過單例模式的好處以及各種實現,有興趣可以了解一下:http://aphysia.cn/archives/designpattern1。除了單例以外,Spring還可以設置其他的作用域,也就是scope="prototype",這就是原型模式,每次來一個請求,都會新創建一個對象,這個對象就是按照原型實例創建的。

原型模式的定義

原型模式,也是創建型模式的一種,是指用原型實例指定創建對象的種類,并且通過拷貝這些原型創建新的對象,簡單來說,就是拷貝。一般適用于:

  • 實例比較復雜,完全創建成本高,直接復制比較簡單
  • 構造函數比較復雜,創建可能產生很多不必要的對象

優點:

  • 隱藏了創建實例的具體細節
  • 創建對象效率比較高
  • 如果一個對象大量相同的屬性,只有少量需要特殊化的時候,可以直接用原型模式拷貝的對象,加以修改,就可以達到目的。

原型模式的實現方式

一般來說,原型模式就是用來復制對象的,那么復制對象必須有原型類,也就是Prototype,Prototype需要實現Cloneable接口,實現這個接口才能被拷貝,再重寫clone()方法,還可以根據不同的類型來快速獲取原型對象。

我們先定義一個原型類Fruit:

public abstract class Fruit implements Cloneable{String name;float price;public String getName() {return name;}public void setName(String name) {this.name = name;}public float getPrice() {return price;}public void setPrice(float price) {this.price = price;}public Object clone() {Object clone = null;try {clone = super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return clone;}@Overridepublic String toString() {return "Fruit{" +"name='" + name + '\'' +", price=" + price +'}';} }

以及拓展了Fruit類的實體類Apple,Pear,Watermelon:

public class Apple extends Fruit{public Apple(float price){name = "蘋果";this.price = price;} } public class Pear extends Fruit{public Pear(float price){name = "雪梨";this.price = price;} } public class Watermelon extends Fruit{public Watermelon(float price){name = "西瓜";this.price = price;} }

創建一個獲取不同水果類的緩存類,每次取的時候,根據不同的類型,取出來,拷貝一次返回即可:

public class FruitCache {private static ConcurrentHashMap<String,Fruit> fruitMap =new ConcurrentHashMap<String,Fruit>();static {Apple apple = new Apple(10);fruitMap.put(apple.getName(),apple);Pear pear = new Pear(8);fruitMap.put(pear.getName(),pear);Watermelon watermelon = new Watermelon(5);fruitMap.put(watermelon.getName(),watermelon);}public static Fruit getFruit(String name){Fruit fruit = fruitMap.get(name);return (Fruit)fruit.clone();} }

測試一下,分別獲取不同的水果,以及對比兩次獲取同一種類型,可以發現,兩次獲取的同一種類型,不是同一個對象:

public class Test {public static void main(String[] args) {Fruit apple = FruitCache.getFruit("蘋果");System.out.println(apple);Fruit pear = FruitCache.getFruit("雪梨");System.out.println(pear);Fruit watermelon = FruitCache.getFruit("西瓜");System.out.println(watermelon);Fruit apple1 = FruitCache.getFruit("蘋果");System.out.println("是否為同一個對象" + apple.equals(apple1));} }

結果如下:

Fruit{name='蘋果', price=10.0} Fruit{name='雪梨', price=8.0} Fruit{name='西瓜', price=5.0} false

再測試一下,我們看看里面的name屬性是不是同一個對象:

public class Test {public static void main(String[] args) {Fruit apple = FruitCache.getFruit("蘋果");System.out.println(apple);Fruit apple1 = FruitCache.getFruit("蘋果");System.out.println(apple1);System.out.println("是否為同一個對象:" + apple.equals(apple1));System.out.println("是否為同一個字符串對象:" + apple.name.equals(apple1.name));} }

結果如下,里面的字符串確實還是用的是同一個對象:

Fruit{name='蘋果', price=10.0} Fruit{name='蘋果', price=10.0} 是否為同一個對象:false 是否為同一個字符串對象:true

這是為什么呢?因為上面使用的clone()是淺拷貝!!!不過有一點,字符串在Java里面是不可變的,如果發生修改,也不會修改原來的字符串,由于這個屬性的存在,類似于深拷貝。如果屬性是其他自定義對象,那就得注意了,淺拷貝不會真的拷貝該對象,只會拷貝一份引用。

這里不得不介紹一下淺拷貝與深拷貝的區別:

  • 淺拷貝:沒有真正的拷貝數據,只是拷貝了一個指向數據內存地址的指針
  • 深拷貝:不僅新建了指針,還拷貝了一份數據內存

如果我們使用Fruit apple = apple1,這樣只是拷貝了對象的引用,其實本質上還是同一個對象,上面的情況雖然對象是不同的,但是Apple屬性的拷貝還屬于同一個引用,地址還是一樣的,它們共享了原來的屬性對象name。

**那如何進行深拷貝呢?**一般有以下方案:

  • 直接 new 對象,這個不用考慮了

  • 序列化與反序列化:先序列化之后,再反序列化回來,就可以得到一個新的對象,注意必須實現Serializable接口。

  • 自己重寫對象的clone()方法

序列化實現深拷貝

序列化實現代碼如下:

創建一個Student類和School類:

import java.io.Serializable;public class Student implements Serializable {String name;School school;public Student(String name, School school) {this.name = name;this.school = school;} } import java.io.Serializable;public class School implements Serializable {String name;public School(String name) {this.name = name;} }

序列化拷貝的類:

import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable;public class CloneUtil {public static <T extends Serializable> T clone(T obj) {T result = null;try {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(obj);objectOutputStream.close();ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);// 返回生成的新對象result = (T) objectInputStream.readObject();objectInputStream.close();} catch (Exception e) {e.printStackTrace();}return result;} }

測試類:

public class Test {public static void main(String[] args) {School school = new School("東方小學");Student student =new Student("小明",school);Student student1= CloneUtil.clone(student);System.out.println(student.equals(student1));System.out.println(student.school.equals(student1.school));} }

上面的結果均是false,說明確實不是同一個對象,發生了深拷貝。

clone實現深拷貝

前面的Student和School都實現Cloneable接口,然后重寫clone()方法:

public class Student implements Cloneable {String name;School school;public Student(String name, School school) {this.name = name;this.school = school;}@Overrideprotected Object clone() throws CloneNotSupportedException {Student student = (Student) super.clone();student.school = (School) school.clone();return student;} } public class School implements Cloneable {String name;public School(String name) {this.name = name;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();} }

測試類:

public class Test {public static void main(String[] args) throws Exception{School school = new School("東方小學");Student student =new Student("小明",school);Student student1= (Student) student.clone();System.out.println(student.equals(student1));System.out.println(student.school.equals(student1.school));} }

測試結果一樣,同樣都是false,也是發生了深拷貝。

總結

原型模式適用于創建對象需要很多步驟或者資源的場景,而不同的對象之間,只有一部分屬性是需要定制化的,其他都是相同的,一般來說,原型模式不會單獨存在,會和其他的模式一起使用。值得注意的是,拷貝分為淺拷貝和深拷貝,淺拷貝如果發生數據修改,不同對象的數據都會被修改,因為他們共享了元數據。

【作者簡介】
秦懷,公眾號【秦懷雜貨店】作者,技術之路不在一時,山高水長,縱使緩慢,馳而不息。個人寫作方向:Java源碼解析,JDBC,Mybatis,Spring,redis,分布式,劍指Offer,LeetCode等,認真寫好每一篇文章,不喜歡標題黨,不喜歡花里胡哨,大多寫系列文章,不能保證我寫的都完全正確,但是我保證所寫的均經過實踐或者查找資料。遺漏或者錯誤之處,還望指正。

劍指Offer全部題解PDF

2020年我寫了什么?

開源編程筆記

關注公眾號 ”秦懷雜貨店“ 可以領取劍指 Offer V1版本的 PDF解法,V2版本增加了題目,還在哼哧哼哧的更新中,并且為每道題目增加了C++解法,敬請期待。

總結

以上是生活随笔為你收集整理的设计模式【5】-- 原型模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。