Monday, January 4, 2021

Prototype Pattern

 原型模式的使用時機

當今天想要複製一個模型裡面的屬性時

並且複製的是原本物件的全部屬性

當今天new可能會造成危害時 

Prototype 使用時機 & 優缺點

有些時候建立物件是非常耗時的,做了很多 IO 操作(DB, file, Api and parse json)才拿到所需要的物件。 

在需要建立類似物件時,會希望耗時操作越少越好,使用 Prototype 就可以減少這類型的消耗。

多執行緒或跨類別操作時可以藉由 Prototype 來避免共享變數,共享變數會造成不可預期的資料修改或是 Deadlock 。 

雖然在原書中該 pattern 沒有限制物件要是 immutable 的,但是在這種情形下搭配 immutable 物件會很適合的。

 缺點是實作 copy 比較繁瑣而且無聊,有些 library 或是語言本身可以幫助你完成這件事,像是 Java 的 Lombok 可以藉由 annotation 自動程式碼,或是 kotlin 的 Arrow 可以生成 Lens (嚴格的來說這並不符合 Prototype Pattern 的定義,但是能夠獲得一樣的效果)。

免在繼承的類別上使用 copy(),尤其是子類別有 override 父類別行為的時候,這時候會因為不同的呼叫時機點而產生難以控制的行為(這裡說的父類別可能是具體類別或是抽象類別,但不包含 interface)。Effective Java 第 17 條這樣說:

 Design and document for inheritance or else prohibit it.

通常這時候你應該要考慮的不是如何安全的實作 copy(),而是考慮使用組合來取代繼承。如果真的需要在繼承的類別實作 copy() 怎麼辦呢?將實作放在子類別吧,抽象類別可以選擇不實作。

应用场景

  • 如果初始化一个类时需要耗费较多的资源,比如数据、硬件等等,可以使用原型拷贝来避免这些消耗。
  • 通过new创建一个新对象时如果需要非常繁琐的数据准备或者访问权限,那么也可以使用原型模式。
  • 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以拷贝多个对象供调用者使用,即保护性拷贝。

优点

  • 可以解决复杂对象创建时消耗过多的问题,在某些场景下提升创建对象的效率。
  • 保护性拷贝,可以防止外部调用者对对象的修改,保证这个对象是只读的。

缺点

  • 拷贝对象时不会执行构造函数。
  • 有时需要考虑深拷贝和浅拷贝的问题



Reference:

https://ithelp.ithome.com.tw/articles/10221129

Android example

=========================================================

public class Intent implements Parcelable, Cloneable {

        //其他代码略

        @Override

        public Object clone() {

            return new Intent(this);//这里没有调用super.clone()来实现拷贝,而是直接通过new来创建

        }

        public Intent(Intent o) {

            this.mAction = o.mAction;

            this.mData = o.mData;

            this.mType = o.mType;

            this.mPackage = o.mPackage;

            this.mComponent = o.mComponent;

            this.mFlags = o.mFlags;

            this.mContentUserHint = o.mContentUserHint;

            if (o.mCategories != null) {

                this.mCategories = new ArraySet<String>(o.mCategories);

            }

            if (o.mExtras != null) {

                this.mExtras = new Bundle(o.mExtras);

            }

            if (o.mSourceBounds != null) {

                this.mSourceBounds = new Rect(o.mSourceBounds);

            }

            if (o.mSelector != null) {

                this.mSelector = new Intent(o.mSelector);

            }

            if (o.mClipData != null) {

                this.mClipData = new ClipData(o.mClipData);

            }

        }

    }

 Uri uri=Uri.parse("smsto:10086");

Intent shareIntent=new Intent(Intent.ACTION_SENDTO,uri);

Intent intent=(Intetn)shareIntent.clone();

startActivity(intent);

=========================================================


No comments:

Post a Comment

n8n index

 【n8n免費本地端部署】Windows版|程式安裝x指令大補帖  【一鍵安裝 n8n】圖文教學,獲得無限額度自動化工具&限時免費升級企業版功能