5분 만에 마스터 프로토타입 모드
안녕하세요 여러분, 저는 Lao Tian입니다. 오늘은 디자인 패턴에 대해 原型模式
여러분과 공유하겠습니다. 적절한 인생 이야기와 실제 프로젝트 시나리오를 사용하여 디자인 패턴에 대해 이야기하고 마지막으로 디자인 패턴을 한 문장으로 요약합니다.
Story
아직도 기억나네요. 4학년 때 일자리를 구하던 중 우연히 인터넷에서 비교적 아름다운 프로그래머 이력서 템플릿을 발견했는데, 그 후 학급 전체가 복사하기 시작했습니다. 미친듯한 이력서 (U disk) 동시에 몇몇 학생들은 자신의 과거 이력서를 내용이나 이름을 바꾸지 않고 그대로 복사해 면접관(캠퍼스 모집 면접관)에게 제출했다는 농담도 나왔다. 나중에는 모두가 결과를 추측할 수 있을 것입니다. 모두가 인턴십에 나섰고, 그들 중 일부는 여전히 일자리를 찾고 있었습니다. 회사 면접관과 다른 반 친구들의 피드백: 똑같은 이력서를 여러 장 받았습니다. 돌아와서 이야기를 나눈 후 모두가 문제가 무엇인지 알고 복사하여 제출했다고 인정했습니다. 전혀 바꾸지 않고.
이력서 사본을 두 가지 유형으로 나눕니다:
하나는 이력서를 복사한 후 내용을 수정하는 방법 다른 하나는 내용을 변경하지 않고 이력서를 복사하는 방법입니다.
프로토타입 패턴 정의
프로토타입 인스턴스를 사용하여 생성할 객체의 종류를 지정하고, 이 프로토타입에 대처하여 새로운 객체를 생성합니다
대략 의미: 객체 생성을 지정합니다. 프로토타입 인스턴스 유형을 사용하고 이러한 프로토타입을 복사하여 새 객체를 생성합니다.
프로토타입 모드: Prototype Pattern
, 창의적인 모드입니다.
호출자는 생성 세부 정보를 알 필요가 없으며 객체를 생성하기 위해 생성자를 호출할 필요도 없습니다.
사용 시나리오
프로토타입 모드에는 다음과 같은 사용 시나리오가 있습니다.
클래스 초기화는 더 많은 리소스를 소비합니다 new로 생성된 객체는 매우 지루한 프로세스(데이터 준비, 액세스 권한 등)가 필요합니다. 생성자가 더 복잡합니다 -
객체는 루프 본문 내에서 생성됩니다 Spring에서는 프로토타입 패턴이 널리 사용됩니다. 예: scope='prototype'
scope='prototype'
我们可以将一些getter和setter之类封装成一个工厂方法,然后对于使用的人来说,调用方法就可以了,不需要知道里面的getter和setter是怎么处理的。我们也可以使用JDK
提供的实现Cloneable
接口,实现快速复制。
创建对象的四种方式:
new、反射、克隆、序列化
实际案例
大家是否有遇到过这种常见,就是项目中规定,不能把与数据库表映射的entity类返回给前端,所以通常返回给前端的有各种O,比如:XxxVO、XxxBO、XxxDTO...
这时候就会出现下面的场景,大家也想已经猜到了。
下面是与数据库表映射的UserEntity
일부 getter 및 setter를 팩토리 메서드로 캡슐화한 다음 사용자를 위해 메서드를 호출하면 됩니다. 내부의 getter와 setter가 어떻게 처리되는지 알 필요가 없습니다. JDK에서 제공되는 구현
복제 가능 인터페이스로 빠른 복사가 가능합니다.
객체를 생성하는 네 가지 방법:
새로 만들기, 반사, 복제, 직렬화🎜
실제 사례
🎜이런 사람이 있나요? 일반적인 문제는 데이터베이스 테이블과 매핑된 엔터티 클래스를 프런트 엔드로 반환할 수 없다고 프로젝트에 규정되어 있으므로 일반적으로 XxxVO, XxxBO, XxxDTO...🎜와 같이 프런트 엔드로 반환되는 다양한 O가 있습니다. 🎜이 때, 다음과 같은 장면이 등장하는데 다들 짐작하셨을 겁니다. 🎜🎜다음은 데이터베이스 테이블UserEntity엔티티 클래스. 🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>public class UserEntity {
private Long id;
private String name;
private Integer age;
//....可能还有很多属性
//省略getter setter
}</pre><div class="contentsignin">로그인 후 복사</div></div>🎜UserVO 엔터티 클래스가 프런트 엔드 또는 호출자에게 반환되었습니다. 🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>public class UserVO {
private Long id;
private String name;
private Integer age;
//....可能还有很多属性
//省略getter setter
}</pre><div class="contentsignin">로그인 후 복사</div></div>🎜이때 데이터베이스에서 찾은 UserEntity를 UserVO로 변환한 후 프런트엔드(또는 호출자)에게 반환해야 합니다. 🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>public class ObjectConvertUtil {
public static UserVo convertUserEntityToUserVO(UserEntity userEntity) {
if (userEntity == null) {
return null;
}
UserVo userVo = new UserVo();
userVo.setId(userEntity.getId());
userVo.setName(userEntity.getName());
userVo.setAge(userEntity.getAge());
//如果还有更多属性呢?
return userVo;
}
}</pre><div class="contentsignin">로그인 후 복사</div></div><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 1px;margin-bottom: 1px;">从这个util类中,我们可以看出,如果一个类的属性有几十个,上百个的,这代码量是不是有点恐怖?</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 1px;margin-bottom: 1px;">于是,我们通常都会使用一些工具类来处理,比如常见有以下:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>BeanUtils.copy();
JSON.parseObject()
Guava工具类
.....</pre><div class="contentsignin">로그인 후 복사</div></div><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 1px;margin-bottom: 1px;">这些工具类就用到了原型模式。</p><blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(239, 112, 96);background: rgb(255, 249, 249);"><p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">通过一个对象,创建一个新的对象。</p></blockquote><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 1px;margin-bottom: 1px;">也把原型模式称之为对象的拷贝、克隆。</p><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 1px;margin-bottom: 1px;">其实对象的克隆分浅克隆和深克隆,下面我们就来聊聊浅克隆和深克隆。</p><ul class="list-paddingleft-2" data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;"><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原来对象的属性所指向的对象的内存地址。</section></li><li><section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);">深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。</section></li></ul><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 1px;margin-bottom: 1px;">我们先来聊聊浅克隆,都喜欢由浅入深。</p><h2 id="span-style-display-none-span-span-style-display-inline-block-background-rgb-color-rgb-padding-px-px-px-border-top-right-radius-px-border-top-left-radius-px-margin-right-px-浅克隆-span-span-style-display-inline-block-vertical-align-bottom-border-bottom-px-solid-efebe-border-right-px-solid-transparent-span"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">浅克隆</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 1px;margin-bottom: 1px;">比如,我现在相对用户信息User进行克隆,但是User中有用户地址信息<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">UserAddress
属性。以下是代码的实现:
//用户地址信息 public class UserAddress implements Serializable{ private String province; private String cityCode; public UserAddress(String province, String cityCode) { this.province = province; this.cityCode = cityCode; } } //用户信息 public class User implements Cloneable { private int age; private String name; //用户地址信息 private UserAddress userAddress; //getter setter 省略 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } //测试 public class UserTest { public static void main(String[] args) throws Exception { User user = new User(); user.setAge(20); user.setName("田维常"); UserAddress userAddress = new UserAddress("贵州", "梵净山"); user.setUserAddress(userAddress); User clone = (User) user.clone(); System.out.println("克隆前后UserAddress比较:" + (user.getUserAddress() == clone.getUserAddress())); } }
输出结果
克隆前后 UserAddress 比较:true
两个对象属性 UserAddress
指向的是同一个地址。
这就是所谓的浅克隆,只是克隆了对象,对于该对象的非基本类型属性,仍指向原来对象的属性所指向的对象的内存地址。
关系如下:
深克隆
关于深克隆,我们来用一个很经典的案例,西游记里的孙悟空。一个孙悟空能变成n多个孙悟空,手里都会拿着一个金箍棒。
按照前面的浅克隆,结果就是:孙悟空倒是变成很多孙悟空,但是金箍棒用的是同一根。
深克隆的结果是:孙悟空变成了很多个,金箍棒也变成很多个根。
下面我们用代码来实现:
//猴子,有身高体重和生日 public class Monkey { public int height; public int weight; public Date birthday; }
孙悟空也是猴子,兵器 孙悟空有个金箍棒:
import java.io.Serializable; //孙悟空的金箍棒 public class JinGuBang implements Serializable{ public float h=100; public float d=10; //金箍棒变大 public void big(){ this.h *=10; this.d *=10; } //金箍棒变小 public void small(){ this.h /=10; this.d /=10; } }
齐天大圣孙悟空:
import java.io.*; import java.util.Date; //孙悟空有七十二变,拔猴毛生成一个金箍棒 //使用JDK的克隆机制, //实现Cloneable并重写clone方法 public class QiTianDaSheng extends Monkey implements Cloneable, Serializable { public JinGuBang jinGuBang; public QiTianDaSheng() { this.birthday = new Date(); this.jinGuBang = new JinGuBang(); } @Override protected Object clone() throws CloneNotSupportedException { return this.deepClone(); } //深克隆 public QiTianDaSheng deepClone() { try { //内存中操作完成、对象读写,是通过字节码直接操作 //与序列化操作类似 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream bis = new ObjectInputStream(bais); //完成一个新的对象,底层是使用new创建的一个对象 //详情可以了解readObject方法 QiTianDaSheng qiTianDaSheng = (QiTianDaSheng) bis.readObject(); //每个猴子的生日不一样,所以每次拷贝的时候,把生日改一下 qiTianDaSheng.birthday = new Date(); return qiTianDaSheng; } catch (Exception ex) { ex.printStackTrace(); return null; } } //浅克隆,就是简单的赋值 public QiTianDaSheng shalllowClone(QiTianDaSheng target) { QiTianDaSheng qiTianDaSheng = new QiTianDaSheng(); qiTianDaSheng.height = target.height; qiTianDaSheng.weight = target.weight; qiTianDaSheng.jinGuBang = target.jinGuBang; qiTianDaSheng.birthday = new Date(); return qiTianDaSheng; } }
接着我们就来测试一下:
public class DeepCloneTest { public static void main(String[] args) { QiTianDaSheng qiTianDaSheng = new QiTianDaSheng(); try { QiTianDaSheng newObject = (QiTianDaSheng) qiTianDaSheng.clone(); System.out.print("深克隆后 "); System.out.println("金箍棒是否一直:" + (qiTianDaSheng.jinGuBang == newObject.jinGuBang)); } catch (Exception ex) { ex.printStackTrace(); } QiTianDaSheng newObject=qiTianDaSheng.shalllowClone(qiTianDaSheng); System.out.print("浅克隆后 "); System.out.println("金箍棒是否一直:" + (qiTianDaSheng.jinGuBang == newObject.jinGuBang)); } }
输出结果为:
深克隆后 金箍棒是否一直:false 浅克隆后 金箍棒是否一直:true
结论
深克隆后每个孙悟空都有自己的金箍棒,而浅克隆后每个孙悟空用的金箍棒实质上还是同一根。
总结
切记:深和浅,指的是克隆对象里的属性(引用类型)是否指向同一个内存地址。
为了更深刻的理解深克隆和浅克隆,我们回答文中的简历拷贝的故事。
딥 카피: 이력서를 복사한 후 이력서의 정보를 수정하여 나만의 이력서로 만드세요. 얕은 카피: 이력서를 복사해도 이력서 내용이 전혀 변경되지 않습니다.
장점:
-
Java 프로토타입 모드는 메모리 바이너리 스트림 복사를 기반으로 하며 직접 새로 작성하는 것보다 성능이 좋습니다. 심층 복제를 사용하여 객체 상태를 저장하고, 이전 복사본을 저장(복제)할 수 있으며, 수정 시 실행 취소 기능으로 작동할 수 있습니다.
단점:
변환 중에 기존 클래스를 수정해야 하며 이는 "열기 및 닫기 원칙"을 위반합니다. 객체 사이에 중첩된 참조가 여러 개 있는 경우 각 레이어를 복제해야 합니다.
프로토타입 패턴의 정의, 사용 시나리오, 실제 사례, 얕은 복제, 깊은 복제, 장점과 단점 등을 포괄적으로 설명했습니다.
위 내용은 5분 만에 마스터 프로토타입 모드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











이 기사에서는 가장 많이 묻는 Java Spring 면접 질문과 자세한 답변을 보관했습니다. 그래야 면접에 합격할 수 있습니다.

Java 8은 스트림 API를 소개하여 데이터 컬렉션을 처리하는 강력하고 표현적인 방법을 제공합니다. 그러나 스트림을 사용할 때 일반적인 질문은 다음과 같은 것입니다. 기존 루프는 조기 중단 또는 반환을 허용하지만 스트림의 Foreach 메소드는이 방법을 직접 지원하지 않습니다. 이 기사는 이유를 설명하고 스트림 처리 시스템에서 조기 종료를 구현하기위한 대체 방법을 탐색합니다. 추가 읽기 : Java Stream API 개선 스트림 foreach를 이해하십시오 Foreach 메소드는 스트림의 각 요소에서 하나의 작업을 수행하는 터미널 작동입니다. 디자인 의도입니다

Java의 TimeStamp to Date 안내. 여기서는 소개와 예제와 함께 Java에서 타임스탬프를 날짜로 변환하는 방법에 대해서도 설명합니다.

캡슐은 3 차원 기하학적 그림이며, 양쪽 끝에 실린더와 반구로 구성됩니다. 캡슐의 부피는 실린더의 부피와 양쪽 끝에 반구의 부피를 첨가하여 계산할 수 있습니다. 이 튜토리얼은 다른 방법을 사용하여 Java에서 주어진 캡슐의 부피를 계산하는 방법에 대해 논의합니다. 캡슐 볼륨 공식 캡슐 볼륨에 대한 공식은 다음과 같습니다. 캡슐 부피 = 원통형 볼륨 2 반구 볼륨 안에, R : 반구의 반경. H : 실린더의 높이 (반구 제외). 예 1 입력하다 반경 = 5 단위 높이 = 10 단위 산출 볼륨 = 1570.8 입방 단위 설명하다 공식을 사용하여 볼륨 계산 : 부피 = π × r2 × h (4

PHP와 Python은 각각 고유 한 장점이 있으며 선택은 프로젝트 요구 사항을 기반으로해야합니다. 1.PHP는 간단한 구문과 높은 실행 효율로 웹 개발에 적합합니다. 2. Python은 간결한 구문 및 풍부한 라이브러리를 갖춘 데이터 과학 및 기계 학습에 적합합니다.

PHP는 서버 측에서 널리 사용되는 스크립팅 언어이며 특히 웹 개발에 적합합니다. 1.PHP는 HTML을 포함하고 HTTP 요청 및 응답을 처리 할 수 있으며 다양한 데이터베이스를 지원할 수 있습니다. 2.PHP는 강력한 커뮤니티 지원 및 오픈 소스 리소스를 통해 동적 웹 컨텐츠, 프로세스 양식 데이터, 액세스 데이터베이스 등을 생성하는 데 사용됩니다. 3. PHP는 해석 된 언어이며, 실행 프로세스에는 어휘 분석, 문법 분석, 편집 및 실행이 포함됩니다. 4. PHP는 사용자 등록 시스템과 같은 고급 응용 프로그램을 위해 MySQL과 결합 할 수 있습니다. 5. PHP를 디버깅 할 때 error_reporting () 및 var_dump ()와 같은 함수를 사용할 수 있습니다. 6. 캐싱 메커니즘을 사용하여 PHP 코드를 최적화하고 데이터베이스 쿼리를 최적화하며 내장 기능을 사용하십시오. 7

Java는 초보자와 숙련된 개발자 모두가 배울 수 있는 인기 있는 프로그래밍 언어입니다. 이 튜토리얼은 기본 개념부터 시작하여 고급 주제를 통해 진행됩니다. Java Development Kit를 설치한 후 간단한 "Hello, World!" 프로그램을 작성하여 프로그래밍을 연습할 수 있습니다. 코드를 이해한 후 명령 프롬프트를 사용하여 프로그램을 컴파일하고 실행하면 "Hello, World!"가 콘솔에 출력됩니다. Java를 배우면 프로그래밍 여정이 시작되고, 숙달이 깊어짐에 따라 더 복잡한 애플리케이션을 만들 수 있습니다.

Spring Boot는 강력하고 확장 가능하며 생산 가능한 Java 응용 프로그램의 생성을 단순화하여 Java 개발에 혁명을 일으킨다. Spring Ecosystem에 내재 된 "구성에 대한 협약"접근 방식은 수동 설정, Allo를 최소화합니다.
