1. 程式人生 > >原型模式(創建型模式)

原型模式(創建型模式)

創建型 args mod 利用 現在 設計模式 構建 第三方 渲染

1、原型模式解決的問題

現在有一個抽象的遊戲設施建造系統,負責構建一個現代風格和古典風格的房屋和道路.

前提:抽象變化較慢,實現變化較快(不穩定)

整個抽象的遊戲設施建造系統相對變化較慢,本例中只有一個Build的創建方法,而Build內部的方法實現,該實現依賴與各種具體的實現,而這些實現變化的非常頻繁,現在雖然只有現代風格和古典風格的房屋和道路的構建,而將來可能會卡通風格、另類風格等各種各樣的對象加入到Build方法中來渲染遊戲的背景.

在不考慮第三方容器組件(如Unity)和設計模式的情況下,為了快速完成這個任務,我們通常會用以下這種方式編碼,代碼如下:

    #region 抽象A
    ///
<summary> /// 抽象的遊戲設施建造系統 /// </summary> public class BuildSystem { /// <summary> /// Build方法的邏輯變化較慢(只需要創建2種風格的房屋和道路,總共8個對象),但是風格變化較快,由於需求變化,可能需要創建諸如卡通風格、另類風格等的房屋和道路 /// </summary> public void Builld() { ModernHouse modernHouseA
= new ModernHouse(); ModernHouse modernHouseB = new ModernHouse(); ModernRoad modernRoadA = new ModernRoad(); ModernRoad modernRoadB = new ModernRoad(); ClassicalHouse classicalBuildA = new ClassicalHouse(); ClassicalHouse classicalBuildB = new
ClassicalHouse(); ClassicalRoad classicalRoadA = new ClassicalRoad(); ClassicalRoad classicalRoadB = new ClassicalRoad(); //下面是具體的對象實例操作,如現代化房屋雖然有兩個實例,但是可能兩個可能高矮、外形不同等 } } #endregion #region 實現細節b /// <summary> /// 現代風格的房屋 /// </summary> public class ModernHouse { } /// <summary> /// 現代風格的道路 /// </summary> public class ModernRoad { } /// <summary> /// 古典風格的房屋 /// </summary> public class ClassicalHouse { } /// <summary> /// 古典風格的道路 /// </summary> public class ClassicalRoad { } #endregion

從oop的角度分析上面的代碼,可以理解為抽象的遊戲系統直接依賴具體的實現細節(現代風格和古典風格的房屋和道路),如下圖:

技術分享圖片

這時客戶端的調用代碼如下:

    /// <summary>
    /// Prototype原型模式-創建型模式
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            BuildSystem buildSystem = new BuildSystem();
            buildSystem.Builld();
        }
    }

這種設計方式的弊端顯而易見,Build方法顯得很無力,這個時候增加了一個新的需求,如下:

客戶端需要構建一種卡通風格和另類風格的道路和房屋,但是Build方法的主邏輯還是不變,同樣是(創建兩種風格的房屋和道路,共8個對象).

這時Build方法顯得很無力,只能創建一種特定邏輯的遊戲背景建築.(當然你可以在BuildSystem中新添一種新的Build方法來滿足需求,但是這種方式的代碼的重用性差)而且,掉到了,抽象依賴於實現的坑裏面去了,這個時候我們就需要對代碼進行重構,進行依賴倒置.如下圖:

技術分享圖片

對所有的Build方法中的8個實例(實現細節b)進行抽象,讓它們依賴於抽象B,讓Build方法(抽象A)也依賴於抽象B,代碼如下:

    #region 抽象A
    /// <summary>
    /// 抽象的遊戲設施建造系統
    /// </summary>
    public class BuildSystem
    {
        /// <summary>
        /// Build方法的邏輯變化較慢(只需要創建2種風格的房屋和道路,總共8個對象),但是風格變化較快,由於需求變化,可能需要創建諸如卡通風格、另類風格等的房屋和道路
        /// </summary>
        public void Builld(House houseone, House houseTwo,Road roadone, Road roadtwo)
        {
            House modernHouseA = houseone.Clone();
            House modernHouseB = houseone.Clone();
            Road modernRoadA = roadone.Clone();
            Road modernRoadB = roadone.Clone();
            House classicalBuildA = houseTwo.Clone();
            House classicalBuildB = houseTwo.Clone();
            Road classicalRoadA = roadtwo.Clone();
            Road classicalRoadB = roadtwo.Clone();
            //下面是具體的對象實例操作,如現代化房屋雖然有兩個實例,但是可能兩個可能高矮、外形不同等
        }
    }
    #endregion

    #region 抽象B
    /// <summary>
    /// 抽象房屋
    /// </summary>
    public abstract class House
    {
        /// <summary>
        /// 抽象的House的Clone方法,用於構建House的多個實例,如果抽象A只需要一個實現b的一個實例,則不需要該方法
        /// </summary>
        /// <returns></returns>
        public abstract House Clone();
    }

    /// <summary>
    /// 抽象道路
    /// </summary>
    public abstract class Road
    {
        /// <summary>
        ///  抽象的Road的Clone方法,用於構建Road的多個實例,如果抽象A只需要一個實現b的一個實例,則不需要該方法
        /// </summary>
        /// <returns></returns>
        public abstract Road Clone();
    }
    #endregion

    #region 實現細節b
    /// <summary>
    /// 現代風格的房屋
    /// </summary>
    public class ModernHouse : House
    {
        public override House Clone()
        {
            //實現ModernHouse的淺拷貝,如果當前對象中含有數組等,則需要使用序列化的方式(深拷貝)實現對象的克隆,否則當一個對象實例修改了數組,另一個對象實例會共享該數組
            return (ModernHouse)MemberwiseClone();
        }
    }

    /// <summary>
    /// 現代風格的道路
    /// </summary>
    public class ModernRoad : Road
    {
        public override Road Clone()
        {
            return (ModernRoad)MemberwiseClone();
        }
    }

    /// <summary>
    /// 古典風格的房屋
    /// </summary>
    public class ClassicalHouse : House
    {
        public override House Clone()
        {
            return (House)MemberwiseClone();
        }
    }

    /// <summary>
    /// 古典風格的道路
    /// </summary>
    public class ClassicalRoad: Road
    {
        public override Road Clone()
        {
            return (ClassicalRoad)MemberwiseClone();
        }
    }

    /// <summary>
    /// 卡通風格的房屋
    /// </summary>
    public class CartoonHouse : House
    {
        public override House Clone()
        {
            return (CartoonHouse)MemberwiseClone();
        }
    }

    /// <summary>
    /// 卡通風格的道路
    /// </summary>
    public class CartoonRoad : Road
    {
        public override Road Clone()
        {
            return (CartoonRoad)MemberwiseClone();
        }
    }

    /// <summary>
    /// 另類風格的房屋
    /// </summary>
    public class AlternativeHouse : House
    {
        public override House Clone()
        {
            return (AlternativeHouse)MemberwiseClone();
        }
    }

    /// <summary>
    /// 另類風格的道路
    /// </summary>
    public class AlternativeRoad : Road
    {
        public override Road Clone()
        {
            return (AlternativeRoad)MemberwiseClone();
        }
    }
    #endregion

這時客戶端的調用代碼如下:

    class Program
    {
        static void Main(string[] args)
        {
            BuildSystem buildSystem = new BuildSystem();
            //構建卡通風格和另類風格的房屋和道路
            buildSystem.Builld(new CartoonHouse(), new AlternativeHouse(), new CartoonRoad(), new AlternativeRoad());
            //構建現代風格和古典風格的房屋和道路
            buildSystem.Builld(new ModernHouse(),new ClassicalHouse(),new ModernRoad(),new ClassicalRoad());
        }
    }

ok,重構後的代碼,在抽象A相對穩定的情況,通過對實現細節b的抽象,讓實現細節b和抽象A都依賴於抽象B,完成了依賴倒置,實現了代碼new的解耦,這就是原型模式!

關於原型模式的幾個要點:

1、Prototype模式用於隔離類對象的使用者和具體類型(易變類)的之間的耦合關系,但是這些易變類必須擁有穩定的接口.

2、Prototype模式對於"如何創建易變類的對象"采用"原型克隆"的方式來做,它使我們能非常靈活動態的創建某些擁有"穩定接口"的新對象.所需的工作僅僅是創建一個新類的對象即原型,然後在需要的地方不斷的Clone.

3、Prototype模式的Clone方法可以利用Object自帶的MemberwiseClone方法,註:該方法只能用於比較簡單的類,只能實現淺拷貝,如果類中包含數組等引用類型,則需要使用序列化方法來實現類型的深拷貝

原型模式(創建型模式)