C#设计模式学习笔记:(3)抽象工厂模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7596897.html,记录一下学习过程以备后续查用。
一、引言
接上一篇C#设计模式学习笔记:简单工厂模式(工厂方法模式前奏篇),通过简单工厂模式的了解,它的缺点就是随着需求的变化我们要不停地修改工厂里
上一篇文章我们讲了工厂方法模式,它是为了解决简单工厂模式所面对的问题:如果我们增加新的产品,工厂类的方法就要修改本身的代码,增加产品越
多,其逻辑越复杂,同时这样的修改也不符合开放闭合原则OCP--对增加代码开放,对修改代码关闭。为了解决简单工厂的问题,我们引出了工厂方法模式,
通过子类化工厂类,解决了工厂类责任的划分,使得产品和相应的工厂一一对应,符合了OCP。
如果我们要设计一套房子,当然我们知道房子是由房顶、地板、窗户、房门等组成的,先设计一套古典风格的房子,再创建一套现代风格的房子,再创建
一套欧式风格的房子,这么多套房子,我们该怎么办呢?今天我们要讲的抽象工厂模式可以很好地解决多套变化的问题。
二、抽象工厂模式介绍
抽象工厂模式:英文名称--Abstract Factory Pattern;分类--创建型。
2.1、动机(Motivate)
在软件系统中,经常面临着"一系列相互依赖的对象"的创建工作,同时,由于需求的变化,往往存在更多系列对象的创建工作。如何应对这种变化?如何
绕过常规的对象创建方法(new),提供一种"封装机制"来避免客户程序和这种"多系列具体对象创建工作"的紧耦合?
2.2、意图(Intent)
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。——《设计模式》GoF
2.3、结构图(Structure)
该图是抽象工厂的UML图,结合抽象工厂的意图、动机和图示来理解该模式,今天我们就以建设房子为例来说明抽象工厂的实现机理。
2.4、模式的组成
从上图可以看出,在抽象工厂模式的结构图有以下角色:
1)抽象产品类角色(AbstractProduct):为抽象工厂中相互依赖的每种产品定义抽象接口对象,也可以这样说,有几种产品,就要声明几个抽象角色,
每一个抽象产品角色和一种具体的产品相匹配。
2)具体产品类(ConcreteProduct):具体产品类实现了抽象产品类,是针对某个具体产品的实现的类型。
3)抽象工厂类角色(AbstractFactory):定义了创建一组相互依赖的产品对象的接口操作,每种操作和每种产品一一对应。
4)具体工厂类角色(ConcreteFactory):实现抽象类里所有抽象接口操作,可以创建某系列具体的产品,这些具体的产品是“抽象产品类角色”的子类。
2.5、抽象工厂模式的具体实现
随着我们年龄的增长,我们也到了结婚的年龄,结婚首要的问题就是房子的问题。假设我有一个很有钱的爸爸(呃,发梦中……),我的哥哥们希望能有
一套欧式风格的房子,再加上田园风光,悠闲自在。而我就不一样了,我希望有一套现代样式的房子。由于房子由房顶、地板、窗户和房门组成(其他组
件暂时省略),每套房子的房顶、地板、窗户和房门都是一个体系的。
下面让我们看看如何使用抽象工厂模式来实现不同房屋的建造:
class Program
{
/// <summary>
/// 房顶抽象类,子类的房顶必须继承该类。
/// </summary>
public abstract class Roof
{
/// <summary>
/// 创建房顶
/// </summary>
public abstract void Create();
} /// <summary>
/// 地板抽象类,子类的地板必须继承该类。
/// </summary>
public abstract class Floor
{
/// <summary>
/// 创建地板
/// </summary>
public abstract void Create();
} /// <summary>
/// 窗户抽象类,子类的窗户必须继承该类。
/// </summary>
public abstract class Window
{
/// <summary>
/// 创建窗户
/// </summary>
public abstract void Create();
} /// <summary>
/// 房门抽象类,子类的房门必须继承该类。
/// </summary>
public abstract class Door
{
/// <summary>
/// 创建房门
/// </summary>
public abstract void Create();
} /// <summary>
/// 欧式的房顶
/// </summary>
public class EuropeanRoof : Roof
{
public override void Create()
{
Console.WriteLine("创建欧式的房顶");
}
} /// <summary>
/// 欧式的地板
/// </summary>
public class EuropeanFloor : Floor
{
public override void Create()
{
Console.WriteLine("创建欧式的地板");
}
} /// <summary>
///欧式的窗户
/// </summary>
public class EuropeanWindow : Window
{
public override void Create()
{
Console.WriteLine("创建欧式的窗户");
}
} /// <summary>
/// 欧式的房门
/// </summary>
public class EuropeanDoor : Door
{
public override void Create()
{
Console.WriteLine("创建欧式的房门");
}
} /// <summary>
/// 现代的房顶
/// </summary>
public class ModernizationRoof : Roof
{
public override void Create()
{
Console.WriteLine("创建现代的房顶");
}
} /// <summary>
/// 现代的地板
/// </summary>
public class ModernizationFloor : Floor
{
public override void Create()
{
Console.WriteLine("创建现代的地板");
}
} /// <summary>
/// 现代的窗户
/// </summary>
public class ModernizationWindow : Window
{
public override void Create()
{
Console.WriteLine("创建现代的窗户");
}
} /// <summary>
/// 现代的房门
/// </summary>
public class ModernizationDoor : Door
{
public override void Create()
{
Console.WriteLine("创建现代的房门");
}
} /// <summary>
/// 抽象工厂类,提供创建不同类型房子的接口。
/// </summary>
public abstract class AbstractFactory
{
//抽象工厂提供创建一系列产品的接口,此处给出了房顶、地板、窗户和房门的创建接口。
public abstract Roof CreateRoof();
public abstract Floor CreateFloor();
public abstract Window CreateWindow();
public abstract Door CreateDoor();
} /// <summary>
/// 欧式风格房子的工厂,负责创建欧式风格的房子。
/// </summary>
public class EuropeanFactory : AbstractFactory
{
//制作欧式房顶
public override Roof CreateRoof()
{
return new EuropeanRoof();
} //制作欧式地板
public override Floor CreateFloor()
{
return new EuropeanFloor();
} //制作欧式窗户
public override Window CreateWindow()
{
return new EuropeanWindow();
} //制作欧式房门
public override Door CreateDoor()
{
return new EuropeanDoor();
}
} /// <summary>
/// 现在风格房子的工厂,负责创建现代风格的房子。
/// </summary>
public class ModernizationFactory : AbstractFactory
{
//制作现代房顶
public override Roof CreateRoof()
{
return new ModernizationRoof();
} //制作现代地板
public override Floor CreateFloor()
{
return new ModernizationFloor();
} //制作现代窗户
public override Window CreateWindow()
{
return new ModernizationWindow();
} //制作现代房门
public override Door CreateDoor()
{
return new ModernizationDoor();
}
} static void Main(string[] args)
{
#region 抽象工厂模式
//欧式风格的房子
AbstractFactory europeanFactory = new EuropeanFactory();
europeanFactory.CreateRoof().Create();
europeanFactory.CreateFloor().Create();
europeanFactory.CreateWindow().Create();
europeanFactory.CreateDoor().Create(); //现代风格的房子
AbstractFactory modernizationFactory = new ModernizationFactory();
modernizationFactory.CreateRoof().Create();
modernizationFactory.CreateFloor().Create();
modernizationFactory.CreateWindow().Create();
modernizationFactory.CreateDoor().Create(); Console.Read();
#endregion
}
}
运行结果如下:
2.6、 抽象工厂模式应对需求变更
假设我的姐姐一看我们的房子很好,她希望有一套古典风格的房子,怎么处理呢?
class Program
{
/// <summary>
/// 房顶抽象类,子类的房顶必须继承该类。
/// </summary>
public abstract class Roof
{
/// <summary>
/// 创建房顶
/// </summary>
public abstract void Create();
} /// <summary>
/// 地板抽象类,子类的地板必须继承该类。
/// </summary>
public abstract class Floor
{
/// <summary>
/// 创建地板
/// </summary>
public abstract void Create();
} /// <summary>
/// 窗户抽象类,子类的窗户必须继承该类。
/// </summary>
public abstract class Window
{
/// <summary>
/// 创建窗户
/// </summary>
public abstract void Create();
} /// <summary>
/// 房门抽象类,子类的房门必须继承该类。
/// </summary>
public abstract class Door
{
/// <summary>
/// 创建房门
/// </summary>
public abstract void Create();
} /// <summary>
/// 欧式的房顶
/// </summary>
public class EuropeanRoof : Roof
{
public override void Create()
{
Console.WriteLine("创建欧式的房顶");
}
} /// <summary>
/// 欧式的地板
/// </summary>
public class EuropeanFloor : Floor
{
public override void Create()
{
Console.WriteLine("创建欧式的地板");
}
} /// <summary>
///欧式的窗户
/// </summary>
public class EuropeanWindow : Window
{
public override void Create()
{
Console.WriteLine("创建欧式的窗户");
}
} /// <summary>
/// 欧式的房门
/// </summary>
public class EuropeanDoor : Door
{
public override void Create()
{
Console.WriteLine("创建欧式的房门");
}
} /// <summary>
/// 现代的房顶
/// </summary>
public class ModernizationRoof : Roof
{
public override void Create()
{
Console.WriteLine("创建现代的房顶");
}
} /// <summary>
/// 现代的地板
/// </summary>
public class ModernizationFloor : Floor
{
public override void Create()
{
Console.WriteLine("创建现代的地板");
}
} /// <summary>
/// 现代的窗户
/// </summary>
public class ModernizationWindow : Window
{
public override void Create()
{
Console.WriteLine("创建现代的窗户");
}
} /// <summary>
/// 现代的房门
/// </summary>
public class ModernizationDoor : Door
{
public override void Create()
{
Console.WriteLine("创建现代的房门");
}
} /// <summary>
///古典的房顶
/// </summary>
public class ClassicalRoof : Roof
{
public override void Create()
{
Console.WriteLine("创建古典的房顶");
}
} /// <summary>
/// 古典的地板
/// </summary>
public class ClassicalFloor : Floor
{
public override void Create()
{
Console.WriteLine("创建古典的地板");
}
} /// <summary>
/// 古典的窗户
/// </summary>
public class ClassicalWindow : Window
{
public override void Create()
{
Console.WriteLine("创建古典的窗户");
}
} /// <summary>
/// 古典的房门
/// </summary>
public class ClassicalDoor : Door
{
public override void Create()
{
Console.WriteLine("创建古典的房门");
}
} /// <summary>
/// 抽象工厂类,提供创建不同类型房子的接口。
/// </summary>
public abstract class AbstractFactory
{
//抽象工厂提供创建一系列产品的接口,此处给出了房顶、地板、窗户和房门的创建接口。
public abstract Roof CreateRoof();
public abstract Floor CreateFloor();
public abstract Window CreateWindow();
public abstract Door CreateDoor();
} /// <summary>
/// 欧式风格房子的工厂,负责创建欧式风格的房子。
/// </summary>
public class EuropeanFactory : AbstractFactory
{
//制作欧式房顶
public override Roof CreateRoof()
{
return new EuropeanRoof();
} //制作欧式地板
public override Floor CreateFloor()
{
return new EuropeanFloor();
} //制作欧式窗户
public override Window CreateWindow()
{
return new EuropeanWindow();
} //制作欧式房门
public override Door CreateDoor()
{
return new EuropeanDoor();
}
} /// <summary>
/// 现在风格房子的工厂,负责创建现代风格的房子。
/// </summary>
public class ModernizationFactory : AbstractFactory
{
//制作现代房顶
public override Roof CreateRoof()
{
return new ModernizationRoof();
} //制作现代地板
public override Floor CreateFloor()
{
return new ModernizationFloor();
} //制作现代窗户
public override Window CreateWindow()
{
return new ModernizationWindow();
} //制作现代房门
public override Door CreateDoor()
{
return new ModernizationDoor();
}
} /// <summary>
/// 古典风格房子的工厂,负责创建古典风格的房子。
/// </summary>
public class ClassicalFactory : AbstractFactory
{
//创建古典房顶
public override Roof CreateRoof()
{
return new ClassicalRoof();
} //创建古典地板
public override Floor CreateFloor()
{
return new ClassicalFloor();
} //创建古典窗户
public override Window CreateWindow()
{
return new ClassicalWindow();
} //创建古典房门
public override Door CreateDoor()
{
return new ClassicalDoor();
}
} static void Main(string[] args)
{
#region 抽象工厂模式
//欧式风格的房子
AbstractFactory europeanFactory = new EuropeanFactory();
europeanFactory.CreateRoof().Create();
europeanFactory.CreateFloor().Create();
europeanFactory.CreateWindow().Create();
europeanFactory.CreateDoor().Create(); //现代风格的房子
AbstractFactory modernizationFactory = new ModernizationFactory();
modernizationFactory.CreateRoof().Create();
modernizationFactory.CreateFloor().Create();
modernizationFactory.CreateWindow().Create();
modernizationFactory.CreateDoor().Create(); //古典风格的房子
AbstractFactory classicalFactory = new ClassicalFactory();
classicalFactory.CreateRoof().Create();
classicalFactory.CreateFloor().Create();
classicalFactory.CreateWindow().Create();
classicalFactory.CreateDoor().Create(); Console.Read();
#endregion
}
}
运行结果如下:
从上面代码可以看出,需要添加5个类:4个类分别创建古典风格的房顶、地板、窗户和房门的具体产品,另外一个是古典风格房子的工厂类,负责创建
古典风格的房子。
从上面代码可以看出,抽象工厂对于系列产品的变化支持开闭原则(对扩展开放,对修改封闭),扩展起来非常简便。但是,抽象工厂对于增加新产品
这种情况就不支持开闭原则,因为要修改创建系列产品的抽象基类AbstractFactory,增加相应产品的创建方法,这也是抽象工厂的缺点所在。
三、抽象工厂模式的实现要点
1)如果没有应对“多系列对象创建”的需求变化,则没有必要使用AbstractFactory模式,这时候使用简单工厂模式完全可以。
2)"系列对象"指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中“道路”与“房屋”的依赖,“道路”与“地道”的依赖。
3)AbstractFactory模式主要在于应对“新系列”的需求变动,其缺点在于难以应对“新对象”的需求变动。
4)AbstractFactory模式经常和FactoryMethod模式共同组合来应对“对象创建”的需求变化。
3.1、抽象工厂模式的优点
抽象工厂模式将系列产品的创建工作延迟到具体工厂的子类中,我们声明工厂类变量的时候使用的是抽象类型,同理,我们使用产品类型也是抽象类型,
这样做可以尽可能地减少客户端代码与具体产品类之间的依赖,从而降低了系统的耦合度。耦合度降低了,对于后期的维护和扩展就更有利,这就是抽象
工厂模式的优点所在。
可能有人会说在Main方法里面(客户端)还是会使用具体的工厂类,对的。这个其实我们可以通过.Net配置文件把这部分移出去,把依赖关系放到配置文
件中。如果有新的需求我们只需要修改配置文件,根本就不需要修改代码了,让客户代码更稳定。依赖关系肯定会存在,我们要做的就是降低依赖,想完全
去除很难,也不现实。
3.2、抽象工厂模式的缺点
有优点肯定就有缺点,因为每种模式都有它的使用范围,或者说不能解决的问题就是缺点。抽象工厂模式很难支持增加新产品的变化,这是因为抽象工厂
接口中已经确定了可以被创建的产品集合,如果需要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类以及所有子类的改变,这样
也就违背了开闭原则。
3.3、抽象工厂模式的使用场景
如果系统需要多套的代码解决方案,并且每套的代码方案中又有很多相互关联的产品类型,并且在系统中可以相互替换地使用一套产品的时候就可以使用
该模式,客户端不需要依赖具体实现。
四、.NET中抽象工厂模式的实现
微软的类库发展了这么多年,设计模式在里面有大量的应用。抽象工厂模式在.NET类库中也存在着大量的使用,比如和操作数据库有关的类型,这个类是
System.Data.Common.DbProviderFactory,此类位于System.Data.dll程序集中。该类扮演抽象工厂模式中抽象工厂的角色,我们可以用ILSpy反编译工具查
看该类的实现:
/// 扮演抽象工厂的角色
/// 创建连接数据库时所需要的对象集合
/// 这个对象集合包括有DbConnection对象(抽象产品类)、DbCommand类、DbDataAdapter类,针对不同的具体工厂都需要实现该抽象类中的方法。
public abstract class DbProviderFactory
{
public virtual bool CanCreateDataSourceEnumerator
{
get
{
return false;
}
} public virtual DbCommand CreateCommand()
{
return null;
} public virtual DbCommandBuilder CreateCommandBuilder()
{
return null;
} public virtual DbConnection CreateConnection()
{
return null;
} public virtual DbConnectionStringBuilder CreateConnectionStringBuilder()
{
return null;
} public virtual DbDataAdapter CreateDataAdapter()
{
return null;
} public virtual DbParameter CreateParameter()
{
return null;
} public virtual CodeAccessPermission CreatePermission(PermissionState state)
{
return null;
} public virtual DbDataSourceEnumerator CreateDataSourceEnumerator()
{
return null;
}
}
DbProviderFactory类是一个抽象工厂类,该类提供了创建数据库连接时所需要的对象集合的接口,实际创建工作在其子类工厂中进行。微软使用的是
SQL Server数据库,因此提供了连接SQL Server数据的具体工厂实现,具体代码可以用反编译工具查看。
SqlClientFactory扮演着具体工厂的角色,用来创建连接SQL Server数据所需要的对象:
public sealed class SqlClientFactory : DbProviderFactory, IServiceProvider
{
public static readonly SqlClientFactory Instance = new SqlClientFactory(); public override bool CanCreateDataSourceEnumerator
{
get
{
return true;
}
} private SqlClientFactory()
{
} public override DbCommand CreateCommand()
{
return new SqlCommand();
} public override DbCommandBuilder CreateCommandBuilder()
{
return new SqlCommandBuilder();
} public override DbConnection CreateConnection()
{
return new SqlConnection();
} public override DbConnectionStringBuilder CreateConnectionStringBuilder()
{
return new SqlConnectionStringBuilder();
} public override DbDataAdapter CreateDataAdapter()
{
return new SqlDataAdapter();
} public override DbParameter CreateParameter()
{
return new SqlParameter();
} public override CodeAccessPermission CreatePermission(PermissionState state)
{
return new SqlClientPermission(state);
} public override DbDataSourceEnumerator CreateDataSourceEnumerator()
{
return SqlDataSourceEnumerator.Instance;
} object IServiceProvider.GetService(Type serviceType)
{
object result = null;
if (serviceType == GreenMethods.SystemDataCommonDbProviderServices_Type)
{
result = GreenMethods.SystemDataSqlClientSqlProviderServices_Instance();
}
return result;
}
}
OdbcFactory也是具体工厂类:
public sealed class OdbcFactory : DbProviderFactory
{
public static readonly OdbcFactory Instance = new OdbcFactory(); private OdbcFactory()
{
} public override DbCommand CreateCommand()
{
return new OdbcCommand();
} public override DbCommandBuilder CreateCommandBuilder()
{
return new OdbcCommandBuilder();
} public override DbConnection CreateConnection()
{
return new OdbcConnection();
} public override DbConnectionStringBuilder CreateConnectionStringBuilder()
{
return new OdbcConnectionStringBuilder();
} public override DbDataAdapter CreateDataAdapter()
{
return new OdbcDataAdapter();
} public override DbParameter CreateParameter()
{
return new OdbcParameter();
} public override CodeAccessPermission CreatePermission(PermissionState state)
{
return new OdbcPermission(state);
}
}
当然,我们也有OleDbFactory类型,都是负责具体的数据库操作。DbProviderFactory就是抽象工厂模式UML里面AbstractFactory类型,其它具体的工厂类
型继承于DbProviderFactory类型。
五、总结
学习设计模式不能死学,要把握核心点和使用场景,关键点是面向对象设计模式的基本原则。有了原则,考虑问题就不会跑偏,然后再仔细把握每种模式的
使用场景和要解决的问题,多写写代码,多看看Net的类库,它是最好的教材。
C#设计模式学习笔记:(3)抽象工厂模式的更多相关文章
- Java设计模式学习笔记(四) 抽象工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...
- Java设计模式学习笔记(二) 简单工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...
- C#设计模式学习笔记:简单工厂模式(工厂方法模式前奏篇)
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7551373.html,记录一下学习过程以备后续查用. 一.引言 简单工厂模式并不属于GoF23里面的设计模式 ...
- C#设计模式学习笔记:(2)工厂方法模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7567880.html,记录一下学习过程以备后续查用. 一.引言 接上一篇C#设计模式学习笔记:简单工厂模式( ...
- Java设计模式(三) 抽象工厂模式
原创文章,同步发自作者个人博客,转载请注明出处 http://www.jasongj.com/design_pattern/abstract_factory/ 抽象工厂模式解决的问题 上文<工厂 ...
- PHP设计模式(三)抽象工厂模式(Abstract Factory)
一.什么是抽象工厂模式 抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象 ,而且使用抽象工厂模式还要满足以下条件: 系统中有多个产品族,而系统一次只可能消费其中一族产品. 同 ...
- C#设计模式学习笔记:(5)原型模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7640873.html,记录一下学习过程以备后续查用. 一.引言 很多人说原型设计模式会节省机器内存,他们说 ...
- C#设计模式学习笔记:(4)建造者模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7614630.html,记录一下学习过程以备后续查用. 一.引言 在现实生活中,我们经常会遇到一些构成比较复杂 ...
- <十一>读<<大话设计模式>>之抽象工厂模式
学习设计模式有一段时间了,对设计模式有一个体会,就是没那么难.就是设计程序遵循一些原则,让代码可复用,在改动的时候不用涉及太多的类,扩展方便.抽象工厂模式名字听起来抽象.但理解起来一点也不抽象,用语言 ...
- 设计模式(3)抽象工厂模式(Abstract Factory)
设计模式(0)简单工厂模式 设计模式(1)单例模式(Singleton) 设计模式(2)工厂方法模式(Factory Method) 源码地址 0 抽象工厂模式简介 0.0 抽象工厂模式定义 抽象工厂 ...
随机推荐
- 理解RabbitMQ中的AMQP-0-9-1模型
前提 之前有个打算在学习RabbitMQ之前,把AMQP详细阅读一次,挑出里面的重点内容.后来找了下RabbitMQ的官方文档,发现了有一篇文档专门介绍了RabbitMQ中实现的AMQP模型部分,于是 ...
- 《算法九》(A星寻路算法)
A星寻路: 结构:N叉树 直线代价斜线代价:符合勾股定理 代价:每走一步,距离终点所付出的 计算公式:f = g + h + w; f : 当前点到终点的代价 g : 起点到当前点的代价 h : 当前 ...
- python笔记16
1.今日内容 模块基础知识 time/datetime json/picle shutil logging 其他 2.内容回顾和补充 2.1模块(类库) 内置 第三方 自定义 面试题: 列举常用内置模 ...
- qt QSplitter分割窗口
#include <QApplication> #include <QFont> #include <QTextEdit> #include <QSplitt ...
- usaco1.1
Your Ride Is Here #include <iostream> #include <string> #include <vector> using na ...
- Newcoder Wannafly13 B Jxy军训(费马小定理、分数在模意义下的值)
链接:https://www.nowcoder.com/acm/contest/80/B 题目描述 在文某路学车中学高一新生军训中,Jxc正站在太阳下站着军姿,对于这样的酷热的阳光,Jxc 表示非常不 ...
- 《剑指Offer》第二章(一)题 9 -12
第二章 面试题9:用两个栈实现队列 题目:如面试题,给你两个栈, 实现队列的先进先出,即在队列头删除一个元素以及在队列的尾部添加一个元素 思路:这个题的分析感觉很巧妙,从一个具体的例子入手,找出其中的 ...
- Golang import具体使用
使用gopath的时候,一般引用是从src下一层开始,比如src/github.com/…,引用github.com…,我的工程src/xxx.com/go-qb/…,引用xxx.com/go-qb/ ...
- Golang设置https访问,以及http如何重定向到https
设置https访问: 原始代码为http监听: func main() { server := &http.Server{ Addr: ":8080", ... } go ...
- 2020年,手把手教你如何在CentOS7上一步一步搭建LDAP服务器的最新教程
同步滚动:关 什么是LDAP 什么是LDAP? 要想知道一个概念,最简单的办法就是wikipedia,当然也可以百科. LDAP全称是轻型目录访问协议(Lightweight Directory Ac ...