延遲加載的原理與代理模式


前言:

本篇涉及的代碼由C#語言描述,但並不妨礙其他語言的面向對象設計師閱讀,旨在理解O/RM延遲加載的原理,減少開發者出現由O/RM引起的性能問題時大叫“怎么會這樣?”的幾率。

本篇並不會詳細介紹代理模式,也不詳細介紹延遲加載,因為這並不是本篇的重點。

本篇隨筆的重點是幫助理解延遲加載的原理,透過這個原理,我們將會知道為什么Nhibernate(O/RM)的領域模型的成員都需要加上virtual關鍵字,也能更好地理解Nhibernate的延遲加載(當然我相信很少會不借助框架而純手工去實現延遲加載)。

我們先來看一個非常簡單的例子:

這個Class1我就暫且當它是一個領域模型,屬性Name是我們需要觀察的延遲加載成員,而ShowStatus是幫助我們觀察延遲加載的狀態。

Class1
public class Class1
    {
        public virtual string Name { get; set; }

        public virtual bool ShowStatus { get; set; }
    }

 

這個Class1Proxy是代理類,我們重寫而來ShowStatus是為了輸出狀態,可以看到我們用override重寫了Name的Get訪問器。

Class1Proxy
internal class Class1Proxy:Class1
    {
        private bool _nameLoaded = false;

        public override bool ShowStatus
        {
            get { return _nameLoaded; }
        }


        public override string Name
        {
            get
            {
                string name;
                if (!_nameLoaded)
                {
                    name = "name was loaded";   //模擬從數據庫加載數據
                    _nameLoaded = true;
                    base.Name = name;   //當做緩存
                }
                else
                {
                    name = base.Name;   //已經加載的情況加使用緩存
                }
                return name;
            }

            set
            {
                base.Name = value;
                _nameLoaded = true;
            }
        }
    }

 

暫時用Mapping類來充當持久化的過程,注意實例化的時候其實是持久化了Proxy,而實際使用當中你不會察覺到你用的是Class1Proxy而不是Class1。

Mapping
    public class Mapping
    {
        public Class1 Build()
        {
            Class1 c1 = new Class1Proxy();
            return c1;
        }
    }

 

測試代碼如下,由於我台式機的IDE正好發生了問題,所以就沒有使用測試框架,直接輸出吧。

VIEW
Class1 c1 = new Class1();
            Mapping mapping = new Mapping();
            c1=mapping.Build();
            Response.Write(c1.ShowStatus+"<br/>");
            Response.Write(c1.Name + "<br/>");
            Response.Write(c1.ShowStatus + "<br/>");

 

輸出結果:

False
name was loaded
True

 

結果可以看到,剛持久化以后Name並沒有被加載(可以看到Mapping.Build方法中並沒有持久化Name),所以輸出了False,然后客戶端試着輸出c1.Name,也就在這時才開始加載Name,然后我們發現輸出時Name已經有數據了。

討論:

在這個例子當中使用了一個簡單的代理,正是因為virtual關鍵字,使得延遲加載得以實現,而實際上在java中所有成員默認就是virtual的,所以在Hibernate中並不需要加這個關鍵字,並不是因為Nhibernate在移植過程中殘疾了,而是本該如此。

如果使用Nhibernate時放棄延遲加載的功能擇可以不必設置動態代理,也就可以不必處處加上virtual關鍵字,但在領域驅動設計中這並不是個好主意。

最后感謝你可以看到這里,希望本篇的介紹會對你有所幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM