面向对象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

版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!

posted @ 2020-07-12 19:54  谢友海  阅读(770)  评论(0编辑  收藏  举报