本系列将和大家分享面向對象23種設計模式中常用的幾種設計模式,本章主要簡單介紹下建立型設計模式。
本章是面向對象23種設計模式系列開篇,首先我們來看下什麼是設計模式?
面向對象23種設計模式:
1、面向對象語言開發過程中,遇到的種種場景和問題,提出了解決方案和思路,沉澱下來就變成了設計模式。
2、解決具體問題的具體招數---套路---站在前輩的肩膀上。
3、沒有什麼設計模式是完美無缺的,一種設計模式就是解決一類問題,通常設計模式在解決一類問題的同時,還會帶來别的問題,我們設計者要做的事兒,就是要揚長避短,充分發揮長處!
設計模式可以大概分為三大類:
1、建立型設計模式:關注對象的建立。
2、結構型設計模式:關注類與類之間的關系。
3、行為型設計模式:關注對象和行為的分離。
我們要做的就是學習核心套路,這裡就不做過多的描述,如果有機會會通過具體例子再和大家分享。下面我們正式進入本章主題。
建立型設計模式:關注對象的建立。(5個)
1、單例模式(Singleton Pattern)
單例模式:
就是限制了對象的建立,重用了對象。保證程序中,某個類隻有一個執行個體。
即使是單例,變量也不是線程安全的,單例不是為了保證線程安全。
單例的好處就是單例,就是全局唯一的一個執行個體。
應對一些特殊情況,比如資料庫連接配接池(内置了資源) ,全局唯一号碼生成器。
單例可以避免重複建立,但是也會常駐記憶體,除非是真的有必要,否則就不要使用單例。
1.1、單例模式經典寫法(懶漢式)
using System;
using System.Threading;
namespace SingletonPattern
{
/// <summary>
/// 懶漢式單例模式(經典寫法)
/// 單例類:一個構造對象很耗時耗資源類型。
/// </summary>
public class Singleton
{
/// <summary>
/// 構造函數耗時耗資源
/// </summary>
private Singleton()
{
long lResult = 0;
for (int i = 0; i < 10000000; i++)
{
lResult += i;
}
Thread.Sleep(2000);
Console.WriteLine("{0}被構造一次", this.GetType().Name);
}
/// <summary>
/// 全局唯一靜态 重用這個變量
/// volatile 促進線程安全 讓線程按順序操作
/// </summary>
private static volatile Singleton _singleton = null;
/// <summary>
/// 引用類型對象
/// </summary>
private static readonly object lockSingleton = new object();
/// <summary>
/// 公開的靜态方法提供對象執行個體
/// </summary>
/// <returns>
/// </returns>
public static Singleton CreateInstance()
{
if (_singleton == null) //_singleton已經被初始化之後,就不要進入鎖等待了
{
//保證任意時刻隻有一個線程進入lock範圍
//也限制了并發,尤其是_singleton已經被初始化之後,故使用了雙if來解決并發限制問題
lock (lockSingleton)
{
//Thread.Sleep(1000);
//Console.WriteLine("等待鎖1s之後才繼續。。。");
if (_singleton == null) //保證隻執行個體化一次
{
_singleton = new Singleton();
}
}
}
return _singleton;
}
public int iTotal = 0;
/// <summary>
/// 既然是單例,大家用的是同一個對象,用的是同一個方法,那還會并發嗎 還有線程安全問題嗎?
/// 即使是單例,變量也不是線程安全的,單例不是為了保證線程安全。
/// </summary>
public void Increment()
{
//lock (lockSingleton)
//{
this.iTotal++;
//}
}
public static void Show()
{
Console.WriteLine(_singleton.iTotal);
}
}
}
使用如下:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace SingletonPattern
{
/// <summary>
/// 為什麼要有單例設計模式?
/// 構造對象耗時耗資源,很多地方都需要去new, 這個方法 其他方法 其他類
/// </summary>
class Program
{
static void Main(string[] args)
{
try
{
{
//保證程序中,某個類隻有一個執行個體
//1 構造函數私有化 避免别人還去new
//2 公開的靜态方法提供對象執行個體
//3 初始化一個靜态字段用于傳回 保證全局都是這一個
Singleton singleton1 = Singleton.CreateInstance();
Singleton singleton2 = Singleton.CreateInstance();
Singleton singleton3 = Singleton.CreateInstance();
Console.WriteLine(object.ReferenceEquals(singleton1, singleton2));
Console.WriteLine(object.ReferenceEquals(singleton3, singleton2));
}
{
List<Task> tasks = new List<Task>();
for (int i = 0; i < 10000; i++)
{
tasks.Add(Task.Run(() =>
{
Singleton singleton = Singleton.CreateInstance();
singleton.Increment();
}));
}
Task.WaitAll(tasks.ToArray());
Singleton.Show();
//即使是單例,變量也不是線程安全的,單例不是為了保證線程安全。
//iTotal 是0 1 10000 還是其他的
//結果為:其他值,1到10000範圍内都可能 線程不安全
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
}
}
1.2、餓漢式寫法(靜态構造函數)
using System;
using System.Threading;
namespace SingletonPattern
{
/// <summary>
/// 餓漢式
/// </summary>
public class SingletonSecond
{
private static SingletonSecond _singletonSecond = null;
/// <summary>
/// 構造函數耗時耗資源
/// </summary>
private SingletonSecond()
{
long lResult = 0;
for (int i = 0; i < 10000000; i++)
{
lResult += i;
}
Thread.Sleep(1000);
Console.WriteLine("{0}被構造一次", this.GetType().Name);
}
/// <summary>
/// 靜态構造函數:由CLR保證,程式第一次使用這個類型前被調用,且隻調用一次。
/// </summary>
static SingletonSecond()
{
_singletonSecond = new SingletonSecond();
Console.WriteLine("SingletonSecond 被啟動");
}
/// <summary>
/// 餓漢式 隻要使用類就會被構造
/// </summary>
/// <returns>
/// </returns>
public static SingletonSecond CreateInstance()
{
return _singletonSecond;
}
}
}
1.3、餓漢式寫法(靜态字段)
using System;
using System.Threading;
namespace SingletonPattern
{
/// <summary>
/// 餓漢式
/// </summary>
public class SingletonThird
{
/// <summary>
/// 靜态字段:在第一次使用這個類之前,由CLR保證,初始化且隻初始化一次。
/// 這個比構造函數還早
/// </summary>
private static SingletonThird _singletonThird = new SingletonThird(); //列印個日志
/// <summary>
/// 構造函數耗時耗資源
/// </summary>
private SingletonThird()
{
long lResult = 0;
for (int i = 0; i < 10000000; i++)
{
lResult += i;
}
Thread.Sleep(1000);
Console.WriteLine("{0}被構造一次", this.GetType().Name);
}
/// <summary>
/// 餓漢式 隻要使用類就會被構造
/// </summary>
/// <returns>
/// </returns>
public static SingletonThird CreateInstance()
{
return _singletonThird;
}
public void Show()
{
Console.WriteLine("這裡是{0}.Show", this.GetType().Name);
}
}
}
2、原型模式(Prototype Pattern)
原型模式:
換個方式建立對象,不走構造函數,而是記憶體拷貝。
單例的基礎上更新了一下,把對象從記憶體層面複制了一下,然後傳回。
是個新對象,但是又不是new出來的。
using System;
using System.Threading;
namespace PrototypePattern
{
/// <summary>
/// 原型模式:單例的基礎上更新了一下,把對象從記憶體層面複制了一下,然後傳回。
/// 是個新對象,但是又不是new出來的。
/// </summary>
public class Prototype
{
/// <summary>
/// 構造函數耗時耗資源
/// </summary>
private Prototype()
{
long lResult = 0;
for (int i = 0; i < 10000000; i++)
{
lResult += i;
}
Thread.Sleep(2000);
Console.WriteLine("{0}被構造一次", this.GetType().Name);
}
/// <summary>
/// 全局唯一靜态 重用這個變量
/// </summary>
private static volatile Prototype _prototype = new Prototype();
/// <summary>
/// 公開的靜态方法提供對象執行個體
/// </summary>
/// <returns>
/// </returns>
public static Prototype CreateInstance()
{
Prototype prototype = (Prototype)_prototype.MemberwiseClone(); //從記憶體層面複制
return prototype;
}
}
}
下面為了示範鼎鼎大名的三大工廠我們建立幾個接口和類:
/// <summary>
/// 種族
/// </summary>
public interface IRace
{
void ShowKing();
}
/// <summary>
/// 軍隊
/// </summary>
public interface IArmy
{
void ShowArmy();
}
/// <summary>
/// 英雄
/// </summary>
public interface IHero
{
void ShowHero();
}
/// <summary>
/// 資源
/// </summary>
public interface IResource
{
void ShowResource();
}
/// <summary>
/// 幸運值
/// </summary>
public interface ILuck
{
void ShowLuck();
}
using System;
using FactoryPattern.War3.Interface;
namespace FactoryPattern.War3.Service
{
/// <summary>
/// 人族(War3種族之一)
/// </summary>
public class Human : IRace
{
public Human(int id, DateTime dateTime, string reamrk)
{ }
public Human()
{ }
public void ShowKing()
{
Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Sky");
}
}
public class HumanArmy : IArmy
{
public void ShowArmy()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "footman,火槍,騎士,獅鹫");
}
}
public class HumanHero : IHero
{
public void ShowHero()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "大法師、山丘、聖騎士、血法師");
}
}
public class HumanResource : IResource
{
public void ShowResource()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "1000G1000W");
}
}
}
using System;
using FactoryPattern.War3.Interface;
namespace FactoryPattern.War3.Service
{
/// <summary>
/// 不死族(War3種族之一)
/// </summary>
public class Undead : IRace
{
public void ShowKing()
{
Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "GoStop");
}
}
public class UndeadArmy : IArmy
{
public void ShowArmy()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "食屍鬼,蜘蛛,雕像,戰車,憎惡,冰霜巨龍");
}
}
public class UndeadHero : IHero
{
public void ShowHero()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "DK、Lich、小強、恐懼魔王");
}
}
public class UndeadResource : IResource
{
public void ShowResource()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "1000G1000W");
}
}
}
using System;
using FactoryPattern.War3.Interface;
namespace FactoryPattern.War3.Service
{
/// <summary>
/// War3種族之一
/// </summary>
public class ORC : IRace
{
public void ShowKing()
{
Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Grubby");
}
}
public class ORCArmy : IArmy
{
public void ShowArmy()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "大G、風騎士、蝙蝠、戰車、牛頭人");
}
}
public class ORCHero : IHero
{
public void ShowHero()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "劍聖、小薩滿、先知、牛頭人酋長");
}
}
public class ORCResource : IResource
{
public void ShowResource()
{
Console.WriteLine("The Army of {0} is {1}", this.GetType().Name, "1000G1000W");
}
}
}
using System;
using FactoryPattern.War3.Interface;
namespace FactoryPattern.War3.Service
{
/// <summary>
/// War3種族之一
/// </summary>
public class NE : IRace
{
public void ShowKing()
{
Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Moon");
}
}
}
3、簡單工廠(Simple Factory)
簡單工廠:不直接new,把對象建立轉移到工廠類。(簡單工廠不屬于23種設計模式)
核心代碼如下:
using System;
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;
namespace SimpleFactory
{
/// <summary>
/// 簡單工廠
/// </summary>
public class ObjectFactory
{
/// <summary>
/// 細節沒有消失 隻是轉移
/// 轉移了沖突,并沒有消除沖突
/// 此處集中了沖突
/// </summary>
/// <param name="raceType">
/// </param>
/// <returns>
/// </returns>
public static IRace CreateRace(RaceType raceType)
{
IRace iRace;
switch (raceType)
{
case RaceType.Human:
iRace = new Human();
break;
case RaceType.Undead:
iRace = new Undead();
break;
case RaceType.ORC:
iRace = new ORC();
break;
case RaceType.NE:
iRace = new NE();
break;
//每增加一個分支就需要修改代碼
default:
throw new Exception("wrong raceType");
}
return iRace;
}
}
/// <summary>
/// 種族類型枚舉
/// </summary>
public enum RaceType
{
Human,
Undead,
ORC,
NE
}
}
using System;
using FactoryPattern.War3.Interface;
namespace SimpleFactory
{
/// <summary>
/// 玩家
/// </summary>
public class Player
{
public int Id { get; set; }
public string Name { get; set; }
/// <summary>
/// 面向抽象
/// </summary>
/// <param name="race">
/// 種族
/// </param>
public void PlayWar3(IRace race)
{
Console.WriteLine("******************************");
Console.WriteLine("This is {0} Play War3.{1}", this.Name, race.GetType().Name);
race.ShowKing();
}
}
}
using System;
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;
namespace SimpleFactory
{
/// <summary>
/// 簡單工廠:非常簡單的工廠
/// 工廠就是建立對象的地方
/// </summary>
class Program
{
static void Main(string[] args)
{
try
{
Player player = new Player()
{
Id = 123,
Name = "候鳥"
};
{
Human human = new Human();//1 到處都是細節
player.PlayWar3(human);
}
{
IRace human = new Human();//2 左邊是抽象 右邊是細節
player.PlayWar3(human);
}
{
IRace human = ObjectFactory.CreateRace(RaceType.Human); //3 沒有細節 細節被轉移
player.PlayWar3(human);
}
{
IRace undead = ObjectFactory.CreateRace(RaceType.Undead); //4 沒有細節 細節被轉移
player.PlayWar3(undead);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
}
}
4、工廠方法模式(Factory Method Pattern)
工廠方法模式:
屏蔽對象的建立,留下了擴充空間。
把簡單工廠拆分成多個工廠,保證每個工廠的相對穩定。
多new一次工廠,難免,中間層,屏蔽業務類變化的影響,而且可以留下建立對象的擴充空間。
using FactoryPattern.War3.Interface;
namespace FactoryMethod.Factory
{
public interface IFactory
{
/// <summary>
/// 建立種族
/// </summary>
/// <returns>
/// </returns>
IRace CreateRace();
}
}
using System;
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;
namespace FactoryMethod.Factory
{
public class HumanFactory : IFactory
{
public virtual IRace CreateRace()
{
return new Human();
}
}
/// <summary>
/// 後期可以對其擴充
/// </summary>
public class HumanFactoryAdvanced : HumanFactory
{
public override IRace CreateRace()
{
Console.WriteLine("123");
return new Human();
}
}
}
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;
namespace FactoryMethod.Factory
{
public class UndeadFactory : IFactory
{
public IRace CreateRace()
{
return new Undead();
}
}
}
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;
namespace FactoryMethod.Factory
{
public class ORCFactory : IFactory
{
public IRace CreateRace()
{
return new ORC();
}
}
}
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;
namespace FactoryMethod.Factory
{
public class NEFactory : IFactory
{
public IRace CreateRace()
{
return new NE();
}
}
}
using System;
using FactoryMethod.Factory;
using FactoryPattern.War3.Interface;
namespace FactoryMethod
{
/// <summary>
/// 工廠方法:把簡單工廠拆分成多個工廠,保證每個工廠的相對穩定。
/// 但是要多new一次工廠? 難免,中間層,屏蔽業務類變化的影響,而且可以留下建立對象的擴充空間。
/// 開閉原則:對擴充開發,對修改封閉。
/// 工廠方法完美遵循了開閉原則
/// </summary>
class Program
{
static void Main(string[] args)
{
try
{
{
//human
IFactory factory = new HumanFactory();//包一層
IRace race = factory.CreateRace();
//何苦 搞了這麼多工廠 還不是建立個對象
//以前依賴的是Human 現在換成了HumanFactory
//1 工廠可以增加一些建立邏輯 屏蔽對象執行個體化的複雜度
//2 對象建立的過程中 可能擴充(尤其是ioc)
}
{
//Undead
IFactory factory = new UndeadFactory();
IRace race = factory.CreateRace();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
}
}
可以看出工廠方法模式,就是把簡單工廠拆分成多個工廠,保證每個工廠的相對穩定。多new一次工廠,難免,中間層,屏蔽業務類變化的影響,而且可以留下建立對象的擴充空間。
另外工廠方法完美遵循了開閉原則,例如:Demo中原先我們有4個種族,分别為Human、Undead、ORC和NE,此時如果業務發生變化需要增加一個Five種族,
這時候我們隻需要添加一個Five工廠類就好了,不會影響原來的代碼。
using System;
using FactoryPattern.War3.Interface;
namespace FactoryPattern.War3.ServiceExtend
{
/// <summary>
/// War3種族之一
/// </summary>
public class Five : IRace
{
public Five()
: this(1, "old", 1) //目前類的構造函數
{
}
public Five(int id, string name, int version)
{
}
public void ShowKing()
{
Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Moon");
}
}
}
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.ServiceExtend;
namespace FactoryMethod.Factory
{
/// <summary>
/// 比如構造很複雜。。比如依賴其他對象
/// 屏蔽變化
/// </summary>
public class FiveFactory : IFactory
{
public virtual IRace CreateRace()
{
//return new Five();
return new Five(2, "New", 2);
}
}
}
5、抽象工廠模式(Abstract Factory Pattern)
抽象工廠模式:
屏蔽對象的建立,限制強制保障産品簇。
建立一組密不可分的對象。
建立産品簇:建立一組密不可分的對象。
工廠+限制
傾斜的可擴充性設計,擴充種族很友善,增加産品很麻煩。
核心代碼如下:
using FactoryPattern.War3.Interface;
namespace AbstractFactory.Factory
{
/// <summary>
/// 一個工廠負責一些産品的建立
/// 産品簇
/// 單一職責就是建立完整的産品簇
///
/// 繼承抽象類後,必須顯式的override父類的抽象方法。
/// </summary>
public abstract class FactoryAbstract
{
public abstract IRace CreateRace();
public abstract IArmy CreateArmy();
public abstract IHero CreateHero();
public abstract IResource CreateResource();
//傾斜的可擴充性設計:擴充種族很友善,增加産品(元素)很麻煩。
//public abstract ILuck CreateLuck(); //增加産品(元素)則每個種族的代碼都要修改
}
}
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;
namespace AbstractFactory.Factory
{
/// <summary>
/// 一個工廠負責一些産品的建立
/// </summary>
public class HumanFactory : FactoryAbstract
{
public override IRace CreateRace()
{
return new Human();
}
public override IArmy CreateArmy()
{
return new HumanArmy();
}
public override IHero CreateHero()
{
return new HumanHero();
}
public override IResource CreateResource()
{
return new HumanResource();
}
}
}
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;
namespace AbstractFactory.Factory
{
/// <summary>
/// 一個工廠負責一些産品的建立
/// </summary>
public class UndeadFactory : FactoryAbstract
{
public override IRace CreateRace()
{
return new Undead();
}
public override IArmy CreateArmy()
{
return new UndeadArmy();
}
public override IHero CreateHero()
{
return new UndeadHero();
}
public override IResource CreateResource()
{
return new UndeadResource();
}
}
}
using System;
using AbstractFactory.Factory;
using FactoryPattern.War3.Interface;
using FactoryPattern.War3.Service;
namespace AbstractFactory
{
/// <summary>
/// 抽象工廠:建立一組密不可分的對象。
/// 建立産品簇:多個對象是個整體,不可分割。
///
/// 工廠+限制
///
/// 傾斜的可擴充性設計:擴充種族很友善,增加産品(元素)很麻煩。
/// </summary>
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("想要玩一款遊戲,必須4大元素備齊");
//System.Data.SqlClient.SqlClientFactory //使用的就是抽象工廠模式
{
IRace race = new Undead();
IArmy army = new UndeadArmy();
IHero hero = new UndeadHero();
IResource resource = new UndeadResource();
//1 對象轉移,屏蔽細節,讓使用者更輕松
//2 對象簇的工廠
}
{
FactoryAbstract undeadFactory = new UndeadFactory();
IRace race = undeadFactory.CreateRace();// new Undead();
IArmy army = undeadFactory.CreateArmy();//new UndeadArmy();
IHero hero = undeadFactory.CreateHero();//new UndeadHero();
IResource resource = undeadFactory.CreateResource();//new UndeadResource();
}
{
FactoryAbstract humanFactory = new HumanFactory();
IRace race = humanFactory.CreateRace();
IArmy army = humanFactory.CreateArmy();
IHero hero = humanFactory.CreateHero();
IResource resource = humanFactory.CreateResource();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
}
}
可以看出抽象工廠模式,屏蔽對象的建立,限制強制保障産品簇,建立一組密不可分的對象(例如:Demo中每個種族都有四個密不可分的元素,分别為Race、Army、Hero和Resource)。
另外抽象工廠模式是傾斜的可擴充性設計,擴充種族很友善,增加産品(元素)很麻煩,例如在Demo中如果産品簇增加一個Luck元素則每個種族的代碼都需要修改。
6、建造者模式(Builder Pattern)
建造者模式:複雜的工廠方法。
Demo源碼:
連結:https://pan.baidu.com/s/1x_quZxEUpCmqqc3Gf-QlFg
提取碼:h1py
此文由部落客精心撰寫轉載請保留此原文連結:https://www.cnblogs.com/xyh9039/p/13258500.html
版權聲明:如有雷同純屬巧合,如有侵權請及時聯系本人修改,謝謝!!!