原型模式
介紹
- 原型模式指用通過(guò)拷貝原型實(shí)例創(chuàng)建新的實(shí)例,新實(shí)例和原型實(shí)例的屬性完全一致
- 原型模式是一種創(chuàng)建型設(shè)計(jì)模式
- 工作原理是通過(guò)調(diào)用原型實(shí)例的
clone()
方法來(lái)完成克隆,原型實(shí)例需要實(shí)現(xiàn)Cloneable接口,并重寫clone()
方法 - 需要為每個(gè)類開(kāi)發(fā)一個(gè)克隆方法,這對(duì)全新的類來(lái)說(shuō)不難,但對(duì)已有類進(jìn)行改造時(shí),需要修改其源代碼,違背了
ocp原則
- 實(shí)現(xiàn)深拷貝的時(shí)候可能需要比較復(fù)雜的代碼
應(yīng)用場(chǎng)景
在以下情況下,我們就不能根據(jù)new 類名()
來(lái)生成實(shí)例,而是克隆現(xiàn)有實(shí)例來(lái)生成新實(shí)例
- 對(duì)象種類繁多,無(wú)法將它們整合到一個(gè)類中(在軟件設(shè)計(jì)中,有時(shí)候我們需要?jiǎng)?chuàng)建一種類型的對(duì)象,但是該類型下有多個(gè)具體的變體,這些變體之間可能存在大量差異,無(wú)法將這些變體都封裝到一個(gè)類中。這時(shí)候可以使用原型模式,將這些變體作為原型,通過(guò)對(duì)原型進(jìn)行克隆來(lái)得到新的對(duì)象。這樣既避免了創(chuàng)建過(guò)多的分類,又能夠保持對(duì)象的個(gè)性化)
-
難以通過(guò)
new
來(lái)創(chuàng)建實(shí)例(有的實(shí)例非常復(fù)雜,想要?jiǎng)?chuàng)建一個(gè)一模一樣的示例非常困難) - 想解耦框架與生成的實(shí)例時(shí)(想要讓生成實(shí)例的框架不依賴于具體的類。這時(shí),不能指定類名來(lái)生成實(shí)例,而要事先“注冊(cè)”一個(gè)“原型”實(shí)例,然后通過(guò)復(fù)制該實(shí)例來(lái)生成新的實(shí)例)
類圖
- Prototype : 原型類,聲明一個(gè)克隆自身的接口
- ConcretePrototype: 具體的原型類,實(shí)現(xiàn)克隆方法
- Client:調(diào)用原型對(duì)象的克隆方法,讓一個(gè)原型對(duì)象克隆自身來(lái)創(chuàng)建一個(gè)屬性一樣的新對(duì)象
案例分析
克隆羊問(wèn)題
現(xiàn)在有一只羊叫做tom,其屬性為姓名: tom,年齡: 1,顏色:白色
,請(qǐng)編寫程序創(chuàng)建和 tom 屬性完全相同
的10只羊。
傳統(tǒng)實(shí)現(xiàn)
package com.atguigu.prototype;
public class Sheep {
private String name;
private int age;
private String color;
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
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 getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
}
}
package com.atguigu.prototype;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//傳統(tǒng)的方法
Sheep sheep = new Sheep("tom", 1, "白色");
Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
Sheep sheep5 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
//....
System.out.println(sheep);
System.out.println(sheep2);
System.out.println(sheep3);
System.out.println(sheep4);
System.out.println(sheep5);
//...
}
}
分析
【優(yōu)點(diǎn)】
- 比較好理解,簡(jiǎn)單易操作
【缺點(diǎn)】
- 在創(chuàng)建新的對(duì)象時(shí),需要獲取原始對(duì)象的屬性,如果創(chuàng)建的對(duì)象比較復(fù)雜時(shí),效率較低,不夠靈活(原型對(duì)象的屬性修改之后,如添加一個(gè)屬性,需要往構(gòu)造方法中添加參數(shù))
- 總是需要重新初始化對(duì)象,而不能動(dòng)態(tài)地獲得對(duì)象運(yùn)行時(shí)的狀態(tài)
【改進(jìn)】
- 使用原型模式:在Java中,
Obiect
類是所有類的根類,Object
類提供了一個(gè)clone()
方法,該方法可以將一個(gè)Java對(duì)象復(fù)制一份,但是需要實(shí)現(xiàn)clone的Java類必須要實(shí)現(xiàn)一個(gè)接口Cloneable
,該接口表示該類能夠復(fù)制且具有復(fù)制的能力
原型模式(淺拷貝)
package com.atguigu.prototype.improve;
/**
* 繼承Cloneable
*/
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
private String address = "蒙古羊";
/**
* 是對(duì)象, 克隆是會(huì)如何處理
*/
public Sheep friend;
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
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 getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]";
}
/**
* 克隆該實(shí)例,使用默認(rèn)的clone方法來(lái)完成
*
* @return
*/
@Override
protected Object clone() {
Sheep sheep = null;
try {
sheep = (Sheep) super.clone();
} catch (Exception e) {
System.out.println(e.getMessage());
}
return sheep;
}
}
package com.atguigu.prototype.improve;
public class Client {
public static void main(String[] args) {
System.out.println("原型模式完成對(duì)象的創(chuàng)建");
Sheep sheep = new Sheep("tom", 1, "白色");
sheep.friend = new Sheep("jack", 2, "黑色");
Sheep sheep2 = (Sheep)sheep.clone();
Sheep sheep3 = (Sheep)sheep.clone();
Sheep sheep4 = (Sheep)sheep.clone();
Sheep sheep5 = (Sheep)sheep.clone();
System.out.println("sheep2 =" + sheep2 + "sheep2.friend=" + sheep2.friend.hashCode());
System.out.println("sheep3 =" + sheep3 + "sheep3.friend=" + sheep3.friend.hashCode());
System.out.println("sheep4 =" + sheep4 + "sheep4.friend=" + sheep4.friend.hashCode());
System.out.println("sheep5 =" + sheep5 + "sheep5.friend=" + sheep5.friend.hashCode());
}
}
原型模式完成對(duì)象的創(chuàng)建
sheep2 =Sheep [name=tom, age=1, color=白色, address=蒙古羊]sheep2.friend=1554874502
sheep3 =Sheep [name=tom, age=1, color=白色, address=蒙古羊]sheep3.friend=1554874502
sheep4 =Sheep [name=tom, age=1, color=白色, address=蒙古羊]sheep4.friend=1554874502
sheep5 =Sheep [name=tom, age=1, color=白色, address=蒙古羊]sheep5.friend=1554874502
Process finished with exit code 0
【分析】
- 根據(jù)輸出,可以看到
其他sheep的friend
和原型對(duì)象的friend
是同一個(gè)對(duì)象(因?yàn)閔ashcode一樣),原因:上面的代碼是淺拷貝
,淺拷貝并不會(huì)重新復(fù)制一個(gè)引用類型的對(duì)象出來(lái),只是單純將克隆對(duì)象的friend指向原型對(duì)象的friend對(duì)象,這樣的壞處是,如果原型對(duì)象的friend發(fā)生了改變,克隆對(duì)象的friend也會(huì)改變,這樣不能算是真正的克隆
原型模式(深拷貝)
package com.atguigu.prototype.deepclone;
import java.io.Serializable;
public class DeepCloneableTarget implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private String cloneName;
private String cloneClass;
/**
* 構(gòu)造器
* @param cloneName
* @param cloneClass
*/
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
/**
* 因?yàn)樵擃惖膶傩?,都是String , 因此我們這里使用默認(rèn)的clone完成即可
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package com.atguigu.prototype.deepclone;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class DeepProtoType implements Serializable, Cloneable {
/**
* 基本數(shù)據(jù)類型
*/
public String name;
/**
* 引用類型
*/
public DeepCloneableTarget deepCloneableTarget;
public DeepProtoType() {
super();
}
/**
* 深拷貝 - 方式 1 使用clone 方法
*
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
//這里完成對(duì)基本數(shù)據(jù)類型(屬性)和String的克隆
Object deep = super.clone();
//對(duì)引用類型的屬性,進(jìn)行單獨(dú)處理
DeepProtoType deepProtoType = (DeepProtoType) deep;
deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
return deepProtoType;
}
/**
* 深拷貝 - 方式2 通過(guò)對(duì)象的序列化實(shí)現(xiàn) (推薦)
* @return
*/
public Object deepClone() {
/// 創(chuàng)建流對(duì)象
// 字節(jié)輸出流
ByteArrayOutputStream bos = null;
// 對(duì)象輸出流
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
//當(dāng)前這個(gè)對(duì)象以對(duì)象流的方式輸出
oos.writeObject(this);
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
DeepProtoType copyObj = (DeepProtoType) ois.readObject();
return copyObj;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
//關(guān)閉流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
System.out.println(e2.getMessage());
}
}
}
}
【客戶端調(diào)用】
package com.atguigu.prototype.deepclone;
public class Client {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
DeepProtoType p = new DeepProtoType();
p.name = "宋江";
p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");
//方式1 完成深拷貝
DeepProtoType p2 = (DeepProtoType) p.clone();
System.out.println("p.name=" + p.name + "; p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
System.out.println("p2.name=" + p.name + "; p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());
//方式2 完成深拷貝
DeepProtoType p3 = (DeepProtoType) p.deepClone();
System.out.println("p3.name=" + p.name + "; p3.deepCloneableTarget=" + p3.deepCloneableTarget.hashCode());
}
}
【運(yùn)行】
p.name=宋江; p.deepCloneableTarget=1554874502
p2.name=宋江; p2.deepCloneableTarget=1846274136
p3.name=宋江; p3.deepCloneableTarget=932172204
Process finished with exit code 0
【分析】
可以看到三個(gè)對(duì)象的deepCloneableTarget的hashCode不同,因此克隆成功
字符串修飾問(wèn)題
【框架】
package framework;
import java.lang.Cloneable;
public interface Product extends Cloneable {
/**
* 實(shí)例使用
* @param s
*/
public abstract void use(String s);
/**
* 實(shí)例復(fù)制
* @return
*/
public abstract Product createClone();
}
package framework;
import java.util.*;
public class Manager {
/**
* 存儲(chǔ)實(shí)例名及實(shí)例
*/
private HashMap showcase = new HashMap();
/**
* 注冊(cè)示例
* @param name
* @param proto
*/
public void register(String name, Product proto) {
showcase.put(name, proto);
}
/**
* 根據(jù)實(shí)例名稱使用實(shí)例
* @param protoname
* @return
*/
public Product create(String protoname) {
Product p = (Product) showcase.get(protoname);
return p.createClone();
}
}
【實(shí)現(xiàn)類】
import framework.*;
/**
* use 方法的作用是將字符串用雙引號(hào)括起來(lái)顯示,并在字符串下面加上下劃線。例如,當(dāng) ulchar 保存的字符為'~' 方法接收到的字符串為Hello時(shí),顯示結(jié)果如下
*
* "Hellor"
* ~~~~~~
*/
public class UnderlinePen implements Product {
private char ulchar;
public UnderlinePen(char ulchar) {
this.ulchar = ulchar;
}
public void use(String s) {
int length = s.getBytes().length;
System.out.println("\"" + s + "\"");
System.out.print(" ");
for (int i = 0; i < length; i++) {
System.out.print(ulchar);
}
System.out.println("");
}
public Product createClone() {
Product p = null;
try {
p = (Product) clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
}
import framework.*;
/**
* decochar字段中保存的是像裝飾方框那樣的環(huán)繞著字符串的字符。use方法會(huì)使用decochar字段中保存的字符把要顯示的字符串框起來(lái)。
* 例如,當(dāng)decochar 中保存的字符為'*',use方法接收到的字符串為 Hello 的時(shí)候,顯示結(jié)果如下
* <p>
* *******
* *Hello*
* *******
*/
public class MessageBox implements Product {
private char decochar;
public MessageBox(char decochar) {
this.decochar = decochar;
}
public void use(String s) {
int length = s.getBytes().length;
for (int i = 0; i < length + 4; i++) {
System.out.print(decochar);
}
System.out.println("");
System.out.println(decochar + " " + s + " " + decochar);
for (int i = 0; i < length + 4; i++) {
System.out.print(decochar);
}
System.out.println("");
}
public Product createClone() {
Product p = null;
try {
p = (Product) clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
}
【主類】
import framework.*;
public class Main {
public static void main(String[] args) {
// 準(zhǔn)備
Manager manager = new Manager();
UnderlinePen upen = new UnderlinePen('~');
MessageBox mbox = new MessageBox('*');
MessageBox sbox = new MessageBox('/');
manager.register("strong message", upen);
manager.register("warning box", mbox);
manager.register("slash box", sbox);
// 生成
Product p1 = manager.create("strong message");
p1.use("Hello, world.");
System.out.println();
Product p2 = manager.create("warning box");
p2.use("Hello, world.");
System.out.println();
Product p3 = manager.create("slash box");
p3.use("Hello, world.");
}
}
"Hello, world."
~~~~~~~~~~~~~
*****************
* Hello, world. *
*****************
/
/ Hello, world. /
/
Process finished with exit code 0
分析
對(duì)象種類繁多,無(wú)法將它們整合到一個(gè)類中時(shí)
在示例程序中,一共出現(xiàn)了如下3種樣式。
- 使用’~'為字符串添加下劃線
- 使用’*'為字符串添加邊框
- 使用’/'為字符串添加邊框
本例比較簡(jiǎn)單,只生成了3種樣式,不過(guò)無(wú)論多少種樣式都可以生成。但是如果將每種樣式都編寫為一個(gè)類,類的數(shù)量將會(huì)非常龐大,源代碼的管理也會(huì)變得非常困難。
想解耦框架與生成的實(shí)例時(shí)
在示例程序中,我們將復(fù)制(clone)實(shí)例的部分封裝在framework
包中了
在Manager類的create方法中,我們并沒(méi)有使用類名,而是根據(jù)"strong message"和"slash box"等字符串(即實(shí)例名稱)來(lái)生成相應(yīng)的實(shí)例。與Java語(yǔ)言自帶的生成實(shí)例的newSomething()方式相比,這種方式具有更好的通用性,且將框架從類名的束縛中解脫出來(lái)了
登場(chǎng)角色
-
Prototype(原型)
:定義用于復(fù)制現(xiàn)有實(shí)例來(lái)生成新實(shí)例的方法,如上面的Product -
ConcretePrototype(具體的原型)
:負(fù)責(zé)實(shí)現(xiàn)復(fù)制現(xiàn)有實(shí)例并生成新實(shí)例的方法,如上面的MessageBox和UnderlinePen -
Client(使用者)
:負(fù)責(zé)使用復(fù)制實(shí)例的方法生成新的實(shí)例,如上面的Manager
Spring源碼分析
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 這里我們的 scope="prototype" 即 原型模式來(lái)創(chuàng)建 -->
<bean id="id01" class="com.atguigu.spring.bean.Monster"
scope="prototype"/>
</beans>
scope=“prototype”:使用原型模式
package com.atguigu.spring.bean;
/**
* 注釋
* @author Administrator
*
*/
public class Monster {
private Integer id = 10 ;
private String nickname = "牛魔王";
private String skill = "芭蕉扇";
public Monster() {
System.out.println("monster 創(chuàng)建..");
}
public Monster(Integer id, String nickname, String skill) {
//System.out.println("Integer id, String nickname, String skill被調(diào)用");
this.id = id;
this.nickname = nickname;
this.skill = skill;
}
public Monster( String nickname, String skill,Integer id) {
this.id = id;
this.nickname = nickname;
this.skill = skill;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
@Override
public String toString() {
return "Monster [id=" + id + ", nickname=" + nickname + ", skill="
+ skill + "]";
}
}
package com.atguigu.spring.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ProtoType {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
// 獲取monster[通過(guò)id獲取monster]
Object bean = applicationContext.getBean("id01");
System.out.println("bean" + bean); // 輸出 "牛魔王" .....
Object bean2 = applicationContext.getBean("id01");
System.out.println("bean2" + bean2); //輸出 "牛魔王" .....
System.out.println(bean == bean2); // false,并不是同一個(gè)對(duì)象,只是屬性相同
}
}
【運(yùn)行】
monster 創(chuàng)建..
beanMonster [id=10, nickname=牛魔王, skill=芭蕉扇]
monster 創(chuàng)建..
bean2Monster [id=10, nickname=牛魔王, skill=芭蕉扇]
false
Process finished with exit code 0
淺拷貝和深拷貝
淺拷貝
- 對(duì)于數(shù)據(jù)類型是
基本數(shù)據(jù)類型
的成員變量,淺拷貝會(huì)直接進(jìn)行值傳遞
,也就是將該屬性值復(fù)制一份給新的對(duì)象 - 對(duì)于數(shù)據(jù)類型是
引用數(shù)據(jù)類型
的成員變量,比如說(shuō)成員變量是某個(gè)數(shù)組、某個(gè)類的對(duì)象等,那么淺拷貝會(huì)進(jìn)行引用傳遞
,也就是只是將該成員變量的引用值 (內(nèi)存地址)復(fù)制一份給新的對(duì)象
。因?yàn)閷?shí)際上兩個(gè)對(duì)象的該成員變量都指同一個(gè)實(shí)例。在這種情況下,在一個(gè)對(duì)象中修改該成員變量會(huì)影響到另一個(gè)對(duì)象的該成員變量值
- sheep = (Sheep) super.clone()這種方式就是淺拷貝
深拷貝
- 復(fù)制對(duì)象的所有基本數(shù)據(jù)類型的成員變量值
為所有引用數(shù)據(jù)類型的成員變量申請(qǐng)存儲(chǔ)空間,并復(fù)制每個(gè)引用數(shù)據(jù)類型成員變量所引用的對(duì)象
【實(shí)現(xiàn)方式】
- 重寫clone方法來(lái)實(shí)現(xiàn)深拷貝(缺點(diǎn):麻煩,每個(gè)子對(duì)象都需要調(diào)用克隆方法重新賦值)
- 通過(guò)對(duì)象序列化實(shí)現(xiàn)深拷貝(缺點(diǎn):速度慢,如果調(diào)用拷貝的次數(shù)多,不要使用這種方式)
深拷貝工具類
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class DeepCloneUtil {
public static Object deepClone(Object srcObject){
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
Object result = null;
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(srcObject);
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
result = ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
}
使用方式文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-604746.html
A a = new A();
A a1 = (A)DeepCloneUtil.deepClone(a);
clone方法與Clonable接口
- Object中定義了clone()方法,如果類實(shí)現(xiàn)了Cloneable接口,就可以調(diào)用clone()來(lái)進(jìn)行實(shí)例復(fù)制;否則調(diào)用就會(huì)報(bào)
CloneNotSupportedException異常
- Cloneable接口中并沒(méi)有聲明任何方法。它只是被用來(lái)標(biāo)記“可以使用clone方法進(jìn)行復(fù)制”的,稱為
標(biāo)記接口(marker interface)
- clone 方法只會(huì)進(jìn)行復(fù)制,并不會(huì)調(diào)用被復(fù)制實(shí)例的構(gòu)造函數(shù)。此外,對(duì)于在生成實(shí)例時(shí)需要進(jìn)行特殊的初始化處理的類,需要自已去實(shí)現(xiàn) clone 方法,在其內(nèi)部進(jìn)行這些初始化處理
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-604746.html
文章說(shuō)明
- 本文章為本人學(xué)習(xí)尚硅谷的學(xué)習(xí)筆記,文章中大部分內(nèi)容來(lái)源于尚硅谷視頻(點(diǎn)擊學(xué)習(xí)尚硅谷相關(guān)課程),也有部分內(nèi)容來(lái)自于自己的思考,發(fā)布文章是想幫助其他學(xué)習(xí)的人更方便地整理自己的筆記或者直接通過(guò)文章學(xué)習(xí)相關(guān)知識(shí),如有侵權(quán)請(qǐng)聯(lián)系刪除,最后對(duì)尚硅谷的優(yōu)質(zhì)課程表示感謝。
- 本人還同步閱讀《圖解設(shè)計(jì)模式》書(shū)籍(圖解設(shè)計(jì)模式/(日)結(jié)城浩著;楊文軒譯–北京:人民郵電出版社,2017.1),進(jìn)而綜合兩者的內(nèi)容,讓知識(shí)點(diǎn)更加全面
到了這里,關(guān)于【設(shè)計(jì)模式——學(xué)習(xí)筆記】23種設(shè)計(jì)模式——原型模式Prototype(原理講解+應(yīng)用場(chǎng)景介紹+案例介紹+Java代碼實(shí)現(xiàn))的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!