设计模式-创建型-建造者模式(Builder)
文章目录
前言
建造者模式属于创建型设计模式,当我们需要一个对象时,而这个对象又存在无比复杂的关系,导致这个对象巨大,那么我们可以通过建造者模式,将一个大对象拆分成多个小对象,分步骤进行创建。所以建造者模式经常用来创建复杂的合成对象,可以自定义配置步骤。
一、建造者模式(Builder)
用来创建复合型对象,将一个原本的大对象拆分成多个小对象,然后可以自定义进行选配组合。
二、应用场景
创建简单对象通常使用工厂模式,而创建复杂对象时可以优先考虑建造者模式
- 相同的方法,不同的执行顺序,产生不同的结果(对象)。
- 多个部件(对象),可以随意拼接到同一对象,但产生的结果有不相同—(乐高)。
- 初始化复杂对象时,参数多并且都具有默认值的情况下。
- 大量的重载构造函数。
三、角色分析
- 产品类(Product):具体的产品
- 抽象建造者(IBuilder):定义产品对象的各个部件的抽象接口。
- 建造者(Builder):实现IBuilder的接口用于构造和装配该产品的各个部件。
- 调用者(Director):指挥调用具体的建造者,来创建对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或者按某种顺序创建。
四、代码实现
1.产品类
先确定相对复杂的产品类
#region Product
/// <summary>
/// CommonUser-Product
/// </summary>
public class User
{
public Guid Id { get; set; } = System.Guid.NewGuid();
public string? Name { get; set; }
public int Age { get; set; }
public Role role { get; set; }
public List<OtherAccount> Accounts { get; set; } = new List<OtherAccount>();
public List<PasswordHistory> passwordList { get; set; } = new List<PasswordHistory>();
}
public class Role
{
public Role(string role)
{
RoleName = role;
}
public string? RoleName { get; set; }
}
public class OtherAccount
{
public OtherAccount(string account)
{
otherAccountNumber = account;
}
public string otherAccountNumber { get; set; }
}
public class PasswordHistory
{
public PasswordHistory(string pwd)
{
password = pwd;
}
public string password { get; set; }
}
#endregion
2.抽象建造者
定义产品对象的各个部件的抽象接口
public interface IUserBuilder
{
User SetUserInfo(string name, int age);
User SetRole(string role);
User SetOtherAccount(string number);
User SetPasswordHistory(string pwd);
}
3.实际建造者
实现Builder的接口用于构造和装配该产品的各个部件
public class UserBuilder : IUserBuilder
{
private User user = new User();
public UserBuilder(User user)
{
this.user = user;
}
public User SetOtherAccount(string number)
{
user.Accounts.Add(new OtherAccount(number));
return user;
}
public User SetPasswordHistory(string pwd)
{
user.passwordList.Add(new PasswordHistory(pwd));
return user;
}
public User SetRole(string role)
{
user.role = new Role(role);
return user;
}
public User SetUserInfo(string name, int age)
{
user.Name = name;
user.Age = age;
return user;
}
}
4.指挥者
用于构造使用Builder接口的对象。
public class DirectorBuilder
{
private UserBuilder userBuilder;
public void SetBuilder(UserBuilder builder)
{
userBuilder = builder;
}
public User CreateObject(
string name,
int age,
string rolename,
string account,
string pwd
)
{
this.userBuilder.SetUserInfo(name, age);
this.userBuilder.SetRole(rolename);
this.userBuilder.SetOtherAccount(account);
var resultUser = this.userBuilder.SetPasswordHistory(pwd);
return resultUser;
}
}
1.0 创建建造者实例
2.0 创建指挥建造者实例
3.0 为指挥者添加工人
4.0 指挥者给工人派活去生产对象产品了
5.0 建造者工人生产完的产品打印
{"Id":"a6b05554-9e25-44e0-9165-cd6e2c8035a4","Name":"Kenny","Age":20,"role":{"RoleName":"admin"},"Accounts":[{"otherAccountNumber":"1234"}],"passwordList":[{"password":"1q2w3E*"}]}
五、建造者模式+原型模式
1.代码实现
建造者模式+原型模式
public interface IUserBuilder
{
User SetUserInfo(string name, int age);
User SetRole(string role);
User SetOtherAccount(string number);
User SetPasswordHistory(string pwd);
}
public class DirectorBuilder
{
private UserBuilder userBuilder;
public void SetBuilder(UserBuilder builder)
{
userBuilder = builder;
}
public User CreateObject(
string name,
int age,
string rolename,
string account,
string pwd
)
{
this.userBuilder.SetUserInfo(name, age);
this.userBuilder.SetRole(rolename);
this.userBuilder.SetOtherAccount(account);
var resultUser = this.userBuilder.SetPasswordHistory(pwd);
return resultUser;
}
}
public class UserBuilder : IUserBuilder
{
private User user = new User();
public UserBuilder(User user)
{
this.user = user;
}
public User SetOtherAccount(string number)
{
user.Accounts.Add(new OtherAccount(number));
return user;
}
public User SetPasswordHistory(string pwd)
{
user.passwordList.Add(new PasswordHistory(pwd));
return user;
}
public User SetRole(string role)
{
user.role = new Role(role);
return user;
}
public User SetUserInfo(string name, int age)
{
user.Name = name;
user.Age = age;
return user;
}
}
/// <summary>
/// 建造者客户端
/// </summary>
public class ClientBuilder
{
public void getObject()
{
Console.WriteLine("1.0 创建建造者实例");
var builder = new UserBuilder(new User());
Console.WriteLine("2.0 创建指挥建造者实例");
var Director = new DirectorBuilder();
Console.WriteLine("3.0 为指挥者添加工人");
Director.SetBuilder(builder);
Console.WriteLine("4.0 指挥者给工人派活去生产对象产品了");
var resultObject = Director.CreateObject("Kenny", 20, "admin", "1234", "1q2w3E*");
Console.WriteLine("4.1 建造者工人生产完的产品打印");
Console.WriteLine(JsonConvert.SerializeObject(resultObject));
Console.WriteLine("4.5 将构建的对象存储到仓库");
ptRepository.AddDictionary(resultObject.GetType().Name.ToString(), resultObject);
Console.WriteLine("4.6 从仓库读取对象");
var user=ptRepository.GetObjectByKey(resultObject.GetType().Name.ToString()) as User;
Console.WriteLine(JsonConvert.SerializeObject(user));
var cloneUser = user.GetCloneNewObject();
Console.WriteLine(JsonConvert.SerializeObject(cloneUser));
cloneUser.Name = "Kenny.Chen";
cloneUser.Age = 10;
cloneUser.Id = System.Guid.NewGuid();
Console.WriteLine(JsonConvert.SerializeObject(cloneUser));
}
}
#region Product
/// <summary>
/// CommonUser-Product
/// </summary>
public class User
{
public Guid Id { get; set; } = System.Guid.NewGuid();
public string? Name { get; set; }
public int Age { get; set; }
public Role role { get; set; }
public List<OtherAccount> Accounts { get; set; } = new List<OtherAccount>();
public List<PasswordHistory> passwordList { get; set; } = new List<PasswordHistory>();
public User GetCloneNewObject()
{
return (User)this.MemberwiseClone();
}
}
public class Role
{
public Role(string role)
{
RoleName = role;
}
public string? RoleName { get; set; }
}
public class OtherAccount
{
public OtherAccount(string account)
{
otherAccountNumber = account;
}
public string otherAccountNumber { get; set; }
}
public class PasswordHistory
{
public PasswordHistory(string pwd)
{
password = pwd;
}
public string password { get; set; }
}
#endregion
#region ProtoTypeRepository
/// <summary>
/// 原型模式仓库
/// sealed:禁止被继承
/// </summary>
public sealed class ptRepository
{
public static Dictionary<string, object> repository = new Dictionary<string, object>();
public static object GetObjectByKey(string key)
{
return repository.Where(p => p.Key.Equals(key)).FirstOrDefault().Value;
}
public static void AddDictionary(string key, object value)
{
repository.Add(key, value);
}
}
#endregion
2.RunLog
1.0 创建建造者实例
2.0 创建指挥建造者实例
3.0 为指挥者添加工人
4.0 指挥者给工人派活去生产对象产品了
4.1 建造者工人生产完的产品打印
{"Id":"144ecdac-7096-4a50-82e7-9fdac1f692f6","Name":"Kenny","Age":20,"role":{"RoleName":"admin"},"Accounts":[{"otherAccountNumber":"1234"}],"passwordList":[{"password":"1q2w3E*"}]}
4.5 将构建的对象存储到仓库
4.6 从仓库读取对象
{"Id":"144ecdac-7096-4a50-82e7-9fdac1f692f6","Name":"Kenny","Age":20,"role":{"RoleName":"admin"},"Accounts":[{"otherAccountNumber":"1234"}],"passwordList":[{"password":"1q2w3E*"}]}
{"Id":"144ecdac-7096-4a50-82e7-9fdac1f692f6","Name":"Kenny","Age":20,"role":{"RoleName":"admin"},"Accounts":[{"otherAccountNumber":"1234"}],"passwordList":[{"password":"1q2w3E*"}]}
{"Id":"a3f535be-23eb-4c58-9028-e7755a470117","Name":"Kenny.Chen","Age":10,"role":{"RoleName":"admin"},"Accounts":[{"otherAccountNumber":"1234"}],"passwordList":[{"password":"1q2w3E*"}]}
总结
优点
- 封装性好,构建和表示分离
- 扩展性好,建造类之间独立,在一定程度上进行了解耦。
- 便于控制细节,建造者可以对创建过程逐步细化,而不对其他模块产生任何影响。
缺点
- 需要多创建IBuilder和DirectorBuilder对象
- 如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。