你应该了解的11 个关键设计模式

作者:微信公众号:【架构师老卢】
9-15 18:58
88

目录

  1. 设计模式 — Abstract Factory
  • 学习目标
  • 开始
  • 如何使用抽象工厂提供程序?
  • 输出

2. 设计模式 — 适配器

  • 用例
  • 学习目标
  • 开始

3. 设计模式 — Builder

  • 用例
  • 学习目标
  • 开始
  • 如何从 Main() 方法使用 builder 模式
  • 输出

4. 如何使用责任链模式

  • 用例
  • 开始
  • 如何使用责任链模式?
  • 输出

5. 设计模式 — Decorator

  • 用例
  • 学习目标
  • 开始
  • Decorator Pattern 的实际应用
  • 完整代码
  • 输出

6. 设计模式 — Factory Method

  • 学习目标
  • 开始
  • 如何使用工厂方法?
  • 输出

7. 设计模式 — 迭代器

  • 用例
  • 开始
  • Iterator 模式的实际应用
  • 输出

8. 设计模式 — 调解人

  • 用例
  • 学习目标
  • 开始
  • 如何使用 main 方法中的中介模式

9. 设计模式 — 观察者

  • 用例
  • 学习目标
  • 开始
  • 如何使用观察者模式?
  • 输出

10. 高级属性模式 C# 8.0

  • 让我们开始吧
  • 具有新 switch 语法的模式匹配程序
  • 测试程序
  • 控制台输出

11. 设计模式 — 单例

  • 学习目标
  • 开始
  • 输出
  • 线程安全

设计模式 — Abstract Factory

根据 Gang of Four 的说法,抽象工厂模式可以被假定为创建工厂的工厂。

学习目标

  • 什么是抽象工厂设计模式?
  • 如何使用抽象工厂设计模式编写代码?
  • 如何创建工厂供应商?
  • 如何创建使用工厂提供程序的客户端应用程序 (从 Main 方法)

先决条件

抽象工厂模式纯粹是一种扩展工厂方法;建议在理解抽象工厂设计之前先完成 Factory 方法。

  • OOPS 概念的基本知识。
  • 任何编程语言知识。

开始

让我们考虑任何具有 Savings 和 Current 账户类型(如 Savings 和 Current accounts)的 Bank 的相同示例。现在让我们使用抽象的工厂设计模式实现上面的例子。

首先,实现 ISavingAccount 和 ICurrentAccount 接口,如下所示:

public interface ISavingAccount{  }  
public interface ICurrentAccount{  }

继承以下类中的接口

public class CurrentAccount : ICurrentAccount  
{  
   public CurrentAccount(string message)  
   {  
    Console.WriteLine(message);  
   }  
}  
public class SavingsAccount : ISavingAccount  
{  
   public SavingsAccount( string message)  
   {  
    Console.WriteLine(message);  
   }  
}

让我们为每种账户类型编写一个包含抽象方法的抽象类。

public abstract class AccountTypeFactory  
{  
  public abstract ISavingAccount SavingAccountFactory(string message);  
  public abstract ICurrentAccount CurrentAccountFactory(string message);  
}

现在,让我们创建一个名为 “Bank1Factory” 的工厂实现,它提供抽象方法的实现。

public class Bank1Factory : AccountTypeFactory  
{  
    public override ICurrentAccount CurrentAccountFactory(string message)  
    {  
        return new CurrentAccount(message);  
    }  
  
    public override ISavingAccount SavingAccountFactory(string message)  
    {  
        return new SavingsAccount(message);  
    }  
}

抽象工厂设计模式不同于实现工厂提供程序所需的工厂方法,后者根据定义返回工厂。

现在我们已经创建了所有的抽象和工厂。让我们设计工厂提供程序。请在下方找到工厂提供程序的代码片段,其中静态方法将根据帐户名称创建工厂。

public class AccountFactoryProvider  
{  
    public static AccountTypeFactory GetAccountTypeFactory(string accountName)  
    {  
      if (accountName.Contains("B1")) { return new Bank1Factory(); }  
        else return null;  
    }  
}

如何使用抽象工厂提供程序?

让我们以一个账号列表为例,如果账户名称由字面上的 “B1” 组成,那么它将使用通过工厂提供程序返回的 Bank1Factory 实例。

static void Main(string[] args)
{
    List<string> accNames = new List<string> { "B1-456", "B1-987", "B2-222" };
    for (int i = 0; i < accNames.Count; i++)
    {
        AccountTypeFactory anAbstractFactory = AccountFactoryProvider.GetAccountTypeFactory(accNames[i]);
        if (anAbstractFactory == null)
        {
            Console.WriteLine("Invalid " + (accNames[i]));
        }
        else
        {
            ISavingAccount savingAccount = anAbstractFactory.SavingAccountFactory("Hello saving");
            ICurrentAccount currentAccount = anAbstractFactory.CurrentAccountFactory("Hello Current");
        }
    }
    Console.ReadLine();
}

如果帐户名称不包含 “B1” 文本,则程序将输出无效的{{accountName}}

输出

请在下面找到上述代码片段的输出。

Hello saving B1-456
Hello Current B1-456
Hello saving B1-987
Hello Current B1-987

设计模式 — 适配器

根据 Gang of Four 的说法,Adapter Pattern 将类的接口转换为客户端需要的接口。

换句话说,适配器设计模式有助于不兼容的接口协同工作。

用例

让我们考虑两个组织合并的示例;X 组织正在接管 Y,但在合并代码时,接口不兼容。假设提供组织 Y 的事务列表的接口与 X 不兼容。

所以适配器设计模式有助于解决这个问题,其实现非常简单。

学习目标

  • 如何使用适配器设计模式进行编码?

开始

让我们创建一个来自组织 Y 的事务列表,这些事务被转换为组织 X 的客户端应用程序所需的模式。上述类称为 “Adaptee”。

public class OrgYTransactions
{
    public List<string> GetTransactionsList()
    {
        List<string> transactions = new List<string>();
        transactions.Add("Debit 1");
        transactions.Add("Debit 2");
        transactions.Add("Debit 3");
        return transactions;
    }
}

其次,让我们创建一个 Target 接口。

public interface ITransactions{  
  List<string> GetTransactions();  
}

现在,让我们最后实现 adapter 类,如下所示。

public class TransAdapter : OrgYTransactions, ITransactions  
{  
    public List<string> GetTransactions()  
    {  
        return GetTransactionsList();  
    }  
}

完成上述所有实现后,让我们了解如何在控制台应用程序中使用 adapter 类。

class Program  
{  
    static void Main(string[] args)  
    {  
        ITransactions adapter = new TransAdapter();  
        foreach (var item in adapter.GetTransactions())  
        {  
            Console.WriteLine(item);  
        }  
    }  
}

如果您仔细查看下面的用法,我们会使用 target 接口和 adapter 类,而没有考虑第三方类接口的外观。这就是适配器设计模式的强大功能:它将类的接口转换为客户端所需的接口。ITransactionsTransAdapterOrgYTransactions

设计模式 — Builder

根据 Gang of Four 的说法,创造模式 “Builder” 允许一个人分离和重用特定方法来构建某些东西。

用例

让我们以一辆汽车为例,用户想要构建两个模型,即 SUV 和 Sedan。

Builder 设计模式在上面的用例中派上用场,让我们看看一个分步演示。

Car 类具有以下属性。

public class Car{  
 public string Name { get; set; }  
 public double TopSpeed { get; set; }  
 public bool IsSUV { get; set; }  
}

学习目标

  • 如何使用构建器设计模式进行编码?

开始

首先,让我们根据用例实现一个抽象类构建器,该构建器由 SUV 或轿车等不同车型扩展。

public abstract class CarBuilder  
{  
    protected readonly Car _car = new Car();  
    public abstract void SetName();  
    public abstract void SetSpeed();  
    public abstract void SetIsSUV();  
    public virtual Car GetCar() => _car;  
}

抽象类由以下方法组成

  • Car 类的每个属性的抽象方法。
  • 输出类实例的虚拟方法。Car

现在,让我们创建一个工厂,该工厂利用类来构建不同的汽车模型,并返回所制造的汽车的实例。CarBuilder

public class CarFactory  
{  
    public Car Build(CarBuilder builder)  
    {  
        builder.SetName();  
        builder.SetSpeed();  
        builder.SetIsSUV();  
        return builder.GetCar();  
    }  
}

最后,实现不同型号的汽车。

ModelSuv.cs

public class ModelSuv : CarBuilder  
{  
    public override void SetIsSUV()  
    {  
        _car.IsSUV = true;  
    }  
  
    public override void SetName()  
    {  
        _car.Name = "Maruti SUV";  
    }  
    public override void SetSpeed()  
    {  
        _car.TopSpeed = 1000;  
    }  
}

ModelSedan.cs

public class ModelSedan : CarBuilder  
{  
    public override void SetIsSUV()  
    {  
        _car.IsSUV = false;  
    }  
  
    public override void SetName()  
    {  
        _car.Name = "Maruti Sedan";  
    }  
    public override void SetSpeed()  
    {  
        _car.TopSpeed = 2000;  
    }  
}

如何从 Main() 方法使用 Builder 模式

最后,让我们使用 design patterns 在 method 的帮助下构建不同的汽车模型。factory.Build(<model>)

static void Main(string[] args)
{
    var sedan = new ModelSedan();
    var suv = new ModelSuv();
    var factory = new CarFactory();
    var builders = new List<CarBuilder> { suv, sedan };
    foreach (var b in builders)
    {
        var c = factory.Build(b);
        Console.WriteLine($"The Car details" +
            $"\n--------------------------------------" +
            $"\nName: {c.Name}" +
            $"\nIs SUV: {c.IsSUV}" +
            $"\nTop Speed: {c.TopSpeed} mph\n");
    }
}

上面的用法显示了我们如何使用 builder 设计模式优雅地构建不同的汽车模型。

该代码模式具有高度可维护性和可扩展性。如果将来我们需要开发一个新模型,只需新模型需要扩展类,就完成了。CarBuilder

输出

如何使用责任链模式

根据 Gang of Four 的说法,它定义了处理请求的职责链。换句话说,将请求从一个对象传递到另一个对象,直到对象接受其责任。

用例

让我们考虑一个公司中的索赔系统示例。以下是可以批准的价格范围列表以及由谁批准。

100–1000 Rs => Junior/Senior Engineers => Approved by Manager  
1001–10000 Rs => Managers => Approved by Senior Manager

如果金额超出 10000 范围,则需要高级经理的例外批准。

上述用例可以使用 Chain of Responsibility 设计模式轻松实现。因此,claim 类具有以下属性。

public class Claim{  
  public int Id{get;set;}  
  public double amount{get;set;}  
}

开始

首先,让我们定义索赔审批者可以执行哪些功能,并为不同级别的员工设置层次结构。实现一个抽象类,如下所示

public abstract class ClaimApprover  
{  
    protected ClaimApprover claimApprover;  
    public void SetHierarchy(ClaimApprover claimApprover)  
    {  
        this.claimApprover = claimApprover;  
    }  
    public abstract void ApproveRequest(Claim claim);  
}

根据用例,让我们驱动类 “junior/senior” 索赔请求者。请注意,此员工类别/指定无法批准任何索赔。

public class Junior : ClaimApprover  
{  
    public override void ApproveRequest(Claim claim)  
    {  
        System.Console.WriteLine("Cannot approve");  
    }  
}

同样,让我们定义 Manager 和 Senior Manager 角色的实现。

public class Manager : ClaimApprover  
{  
    public override void ApproveRequest(Claim claim)  
    {  
        if (claim.amount >= 100 && claim.amount \<= 1000)  
        {  
            System.Console.WriteLine($"Claim reference {claim.Id} with amount {claim.amount} is approved by Manager");  
        }  
        else if (claimApprover != null)  
        {  
            claimApprover.ApproveRequest(claim);  
        }  
    }  
}

注意,根据金额范围,如果在 Manager 的范围内,则 Manager 可以批准索赔;否则,请求将传递给高级经理。

public class SeniorManager : ClaimApprover  
{  
    public override void ApproveRequest(Claim claim)  
    {  
        if (claim.amount > 1000 && claim.amount <= 10000)  
        {  
            System.Console.WriteLine($"Claim reference {claim.Id} with amount {claim.amount} is approved by Senior Manager");  
        }  
        else  
        {  
            System.Console.WriteLine($"Exceptional approval for Claim reference {claim.Id} with amount {claim.amount} is approved by Senior Manager");  
        }  
    }  
}

同样,如果金额范围在 Senior Manager 范围内,则索赔可以由 Manager 批准;否则,在层次结构中排在最后,将对超出范围的金额进行例外审批。

ClaimApprover junior = new Manager();  
ClaimApprover sukhpinder = new Manager();  
ClaimApprover singh = new SeniorManager();  
junior.SetHierarchy(sukhpinder);  
sukhpinder.SetHierarchy(singh);  
  
Claim c1 = new Claim() { amount = 999, Id = 1001 };  
Claim c2 = new Claim() { amount = 10001, Id = 1002 };  
junior.ApproveRequest(c1);  
sukhpinder.ApproveRequest(c2);

如何使用责任链模式?

  1. 定义索赔审批者:初级,尽管它无法批准任何索赔。
  2. 定义索赔审批者:经理 “sukhpinder”。
  3. 定义索赔审批者:高级经理“Singh”。
  4. 为 junior(初级)设置层次结构关系,即索赔审批者是经理。
  5. 为经理设置层次结构关系,即索赔审批者是高级经理。
  6. 创建两个不同的索赔范围。
  7. Junior 将索赔请求发送给经理。
  8. 经理将索赔请求发送给高级经理。

输出

Claim reference 1001 with amount 999 is approved by Manager  
Exceptional approval for Claim reference 1002 with amount 10001 is approved by Senior Manager

对于第 1 行输出,金额在范围内,因此经理批准了它。

对于 2 号线的产量,虽然高级经理批准了,但金额超出了范围。

设计模式 — Decorator

根据 Gang of Four 的说法,该模式动态地向类对象添加了额外的责任。

用例

让我们考虑购买价值十万的汽车的例子;该公司提供以下附加功能

  • 天窗
  • 高级音乐系统
  • 以及更多

通过一些附加功能,汽车的总价会增加。让我们使用 Decorator Pattern 实现上述用例。

学习目标

  • 如何使用装饰器设计模式进行编码?

开始

让我们实现上面定义的用例。首先定义一个抽象类 Car 及其基方法。

public abstract class Car{  
  public abstract int CarPrice();  
  public abstract string GetName();  
}

考虑一个延伸到抽象类 Car 上方的小汽车。

public class SmallCar : Car{  
  public override int CarPrice() => 10000;  
  public override string GetName() => "Alto Lxi";  
}

现在使用组件实现类。CarDecoratorCar

public class CarDecorator : Car  
{  
    protected Car _car;  
    public CarDecorator(Car car)  
    {  
        _car = car;  
    }  
    public override int CarPrice() => _car.CarPrice();  
    public override string GetName() =>_car.GetName();  
}

现在,让我们为可用于继承该类的每个附加功能创建一个单独的类。CarCarDecorator

根据用例,附加功能是天窗和高级音乐系统。

AdvanceMusic.cs

将方法覆盖为

  • 将“高级音乐系统”的额外费用添加到汽车总价中。
  • 使用其他功能名称更新汽车名称。
public class AdvanceMusic : CarDecorator  
{  
    public AdvanceMusic(Car car) : base(car)  
    {  
    }  
  
public override int CarPrice() => \_car.CarPrice() + 3000;  
    public override string GetName()=> "Alto Lxi with advance music system";  
}

Sunroof.CS

将方法覆盖为

  • 将“天窗”的额外成本添加到汽车总价中。
  • 使用其他功能名称更新汽车名称。
public class Sunroof : CarDecorator  
{  
    public Sunroof(Car car) : base(car)  
    {  
    }  
    public override int CarPrice() => _car.CarPrice() + 2000;  
    public override string GetName() => "Alto Lxi with Sunroof";  
}

Decorator Pattern 的实际应用

创建 的实例并输出 car 的名称和价格。SmallCar

Car car = new SmallCar();Console.WriteLine($"Price of car {car.GetName()} : " + car.CarPrice());

现在,让我们添加其他功能,如下所示

var car1 = new Sunroof(car);  
var car2 = new AdvanceMusic(car);

完整代码

static void Main(string[] args)  
{  
    Car car = new SmallCar();  
    Console.WriteLine($"Price of car {car.GetName()} : " + car.CarPrice());  
    var car1 = new Sunroof(car);  
    Console.WriteLine($"Price of car {car1.GetName()} : " + car1.CarPrice());  
    var car2 = new AdvanceMusic(car);  
    Console.WriteLine($"Price of car {car2.GetName()} : " + car2.CarPrice());  
}

输出

祝贺。。!!您已成功使用 decorator 模式实现用例。

设计模式 — 工厂方法

根据 Gang of Four 的说法,工厂方法允许子类确定应该创建哪个类对象。

学习目标

  • 什么是工厂方法设计模式?
  • 如何使用工厂方法编写代码?

开始

让我们考虑一个账户类型为 Savings 和 Current accounts (储蓄账户) 和 Current accounts (活期账户) 的银行示例。现在让我们使用工厂设计模式实现上面的示例

首先,创建一个账户类型的抽象类。

public abstract class AccoutType  
{  
   public string Balance { get; set; }  
}

实现继承 AccountType 抽象类的 current 和 saving account 类,如下所示。

public class SavingsAccount : AccoutType  
{  
 public SavingsAccount()  
 {  
  Balance = "10000 Rs";  
 }  
}  
public class CurrentAccount : AccoutType  
{  
 public CurrentAccount()  
 {  
  Balance = "20000 Rs";  
 }  
}

最后,让我们实现工厂接口,它将提供一个有助于创建类对象的协定。此接口也称为 Creator。

public interface IAccountFactory  
{  
  AccoutType GetAccoutType(string accountName);  
}

最后,编写 creator 接口方法的实现,如下所示。实现 creator 的类称为 Concrete Creator。

public class AccountFactory : IAccountFactory  
{  
    public AccoutType GetAccoutType(string accountName)  
    {  
        if (accountName.Equals("SAVINGS", StringComparison.OrdinalIgnoreCase))  
        {  
            return new SavingsAccount();  
        }  
        else if (accountName.Equals("CURRENT", StringComparison.OrdinalIgnoreCase))  
        {  
            return new CurrentAccount();  
        }  
        else  
        {  
            throw new ArgumentException("Invalid account name");  
        }  
    }  
}

就是这样。您已使用 Bank 示例成功实现了工厂方法。

如何使用工厂方法?

子类将根据帐户名称决定将创建哪个 “AccountType ” 类对象。

class Program  
{  
    static void Main(string[] args)  
    {  
        IAccountFactory accountFactory = new AccountFactory();  
        var savingAccount = accountFactory.GetAccoutType("SAVINGS");  
        Console.WriteLine("Saving account balance: " + savingAccount.Balance);  
        var currentAccount = accountFactory.GetAccoutType("CURRENT");  
        Console.WriteLine("Current account balance: " + currentAccount.Balance);  
    }  
}

例如,如果帐户名称为 “SAVINGS”,则将创建并返回 “SavingAccount” 类对象。

同样,如果帐户名称为 “CURRENT”,则将实例化并返回 “CurrentAccount” 类对象。

输出

Saving account balance: 10000 Rs  
Current account balance: 20000 Rs

设计模式 — Iterator

根据 Gang of Four 的说法,迭代器模式提供了一个在不知道其实现的情况下获取聚合器对象的过程。

用例

让我们以一个汽车集合和一系列摩托车为例,我们需要设计一个聚合器对象,以便人们可以在不知道它是 a 还是 .liststring[]listarray

迭代器设计模式有助于解决此问题,其中标准迭代器将遍历不同的集合类型。

开始

考虑到上述用例,让我们定义一个自定义迭代器接口,它充当列表和数组迭代器上的抽象层。

public interface IVehicleIterator{  
  void First();  
  bool IsDone();  
  string Next();  
  string Current();  
}

现在根据用例编写实现上述接口的 car 和 motorcycle 迭代器。

CarIterator.cs

public class CarIterator : IVehicleIterator  
{  
    private List<string> _cars;  
    private int _current;  
    public CarIterator(List<string> cars)  
    {  
        _cars = cars;  
        _current = 0;  
    }  
    public string Current()  
    {  
        return _cars.ElementAt(_current);  
    }  
    public void First()  
    {  
        _current = 0;  
    }  
    public bool IsDone()  
    {  
        return _current >= _cars.Count;  
    }  
    public string Next()  
    {  
        return _cars.ElementAt(_current++);  
    }  
}

car 迭代器是通过 collection 实现的,并提供接口方法的实现。List<string>

MotorcycleIterator.cs

摩托车迭代器是通过 collection 实现的,并提供接口方法的实现。string[]

public class MotercycleIterator : IVehicleIterator  
{  
    private string[] _motercylces;  
    private int _current;  
    public MotercycleIterator(string[] motercylces)  
    {  
        _motercylces = motercylces;  
        _current = 0;  
    }  
    public string Current()  
    {  
        return _motercylces[_current\];  
    }  
  
    public void First()  
    {  
        _current = 0;  
    }  
    public bool IsDone()  
    {  
        return _current >= _motercylces.Length;  
    }  
    public string Next()  
    {  
        return _motercylces[_current++];  
    }  
}

定义上述所有迭代器后,定义一个创建迭代器的标准聚合器对象接口。

public interface IVehicleAggregate{  
   IVehicleIterator CreateIterator();  
}

最后,写下实现上述 aggregator 接口的类。根据用例,Car 和 Motorcycle 类都将实现聚合器接口。

Car。CS

聚合器接口的方法返回相关的迭代器,如下所示。

public class Car : IVehicleAggregate  
{  
    private List<string> _cars;  
    public Car()  
    {  
        _cars = new List<string> { "Car 1", "Car 2", "Car 3" };  
    }  
  
    public IVehicleIterator CreateIterator()  
    {  
        return new CarIterator(_cars);  
    }  
}

摩托车。CS

聚合器接口的方法返回相关的迭代器,如下所示。

public class Motercycle : IVehicleAggregate  
{  
  private string[] _motercycles;  
    public Motercycle()  
    {  
        _motercycles = new[] { "Bike 1", "Bike 2", "Bike 3" };  
    }  
    public IVehicleIterator CreateIterator()  
    {  
        return new MotercycleIterator(_motercycles);  
    }  
}

Iterator 模式的实际应用

这些方法检查是否随后输出 collection 元素。无论我们处理的是哪个集合,都要实现 First、IsDone 和 Next 等方法。PrintVehicles!iterator.isDone

static void Main(string[] args)  
{  
    IVehicleAggregate car = new Vehicles.Car();  
    IVehicleAggregate motercycle = new Vehicles.Motercycle();  
    IVehicleIterator carIterator = car.CreateIterator();  
    IVehicleIterator motercycleIterator = motercycle.CreateIterator();  
    PrintVehicles(carIterator);  
    PrintVehicles(motercycleIterator);  
}  
static void PrintVehicles(IVehicleIterator iterator)  
{  
    iterator.First();  
    while (!iterator.IsDone())  
    {  
        Console.WriteLine(iterator.Next());  
    }  
}

输出

我们不知道底层的集合类型,但它仍然通过 Iterator Design Pattern 进行迭代。如果您继续运行,它将显示以下输出。

设计模式 — 中介

根据 Gang of Four 的说法,Mediator 模式封装了对象彼此之间的交互。

中介器设计模式通过封装对象交互来帮助我们设计松散耦合的应用程序。

用例

让我们考虑一个参与者注册的聊天室示例,以及如何有效地进行通信。

需要使用 Mediator Design Pattern 实现以下聊天室对话。

David to Scott: 'Hey'  
Scott to David: 'I am good how about you.'  
Jennifer to Ashley: 'Hey ashley... david is back in the group'  
Jennifer to David: 'Where have you been?'  
Ashley to David: 'How come you aren't active here anymore?'

学习目标

  • 如何使用中介器设计模式进行编码?

开始

主要步骤是创建将在聊天室内使用的用户名列表。该函数的 public 枚举如下所示。

public enum Username{  
Ashley,  
David,  
Jennifer,  
Scott  
}

现在,首先实现聊天室的抽象层。

public abstract class AChatroom  
{  
    public abstract void Register(User user);  
    public abstract void Post(string fromUser, string toUser, string msg);  
}

以及一个定义抽象方法的类。这些方法验证用户是否存在于字典中。例如,register 方法验证用户是否已存在。如果不存在,则仅在聊天室中注册用户。

public class Chatroom : AChatroom  
{  
    private Dictionary<string, User> _users = new Dictionary<string, User>();  
    public override void Post(string fromUser, string toUser, string msg)  
    {  
        User participant = _users[toUser];  
        if (participant != null)  
        {  
            participant.DM(fromUser, msg);  
        }  
    }  
    public override void Register(User user)  
    {  
        if (!_users.ContainsValue(user))  
        {  
            _users[user.Name] = user;  
        }  
        user.Chatroom = this;  
    }  
}

最后,让我们实现用户可以执行的操作,例如在聊天室中向用户发布消息或接收来自其他用户的 DM。

public class User  
{  
    private Chatroom _chatroom;  
    private string _name;  
    public User(string name) => this._name = name;  
    public string Name => _name;  
    public Chatroom Chatroom  
    {  
        set { _chatroom = value; }  
        get => _chatroom;  
    }  
    public void Post(string to, string message) =>   
        _chatroom.Post(_name, to, message);  
    public virtual void DM(string from, string message) =>   
        Console.WriteLine("{0} to {1}: '{2}'", from, Name, message);  
}

如何使用 main 方法中的中介模式

static void Main(string[] args)  
{  
    Chatroom chatroom = new Chatroom();  
    User Jennifer = new UserPersona(Username.Jennifer.ToString());  
    User Ashley = new UserPersona(Username.Ashley.ToString());  
    User David = new UserPersona(Username.David.ToString());  
    User Scott = new UserPersona(Username.Scott.ToString());  
      
    chatroom.Register(Jennifer);  
    chatroom.Register(Ashley);  
    chatroom.Register(David);  
    chatroom.Register(Scott);  
  
    David.Post(Username.Scott.ToString(), "Hey");  
    Scott.Post(Username.David.ToString(), "I am good how about you.");  
    Jennifer.Post(Username.Ashley.ToString(), "Hey ashley... david is back in the group");  
    Jennifer.Post(Username.David.ToString(), "Where have you been?");  
    Ashley.Post(Username.David.ToString(), "How come you aren't active here anymore?");  
    Console.ReadKey();  
}
  1. Chatroom 类对象。
  2. 创建了四个具有唯一名称的不同用户。
  3. 在聊天室中注册他们每个人。
  4. 用户现在可以开始相互发布消息。

程序执行仅描述 user 类的方法。Post

**输出:**上述程序执行的聊天室历史

David to Scott: 'Hey'  
Scott to David: 'I am good how about you.'  
Jennifer to Ashley: 'Hey ashley... david is back in the group'  
Jennifer to David: 'Where have you been?'  
Ashley to David: 'How come you aren't active here anymore?'

设计模式 — Observer

根据 Gang of Four 的说法,观察者模式定义了两个或多个对象的依赖关系。因此,当一个对象状态发生更改时,会通知其所有依赖项。

换句话说,一个对象中的更改会在另一个对象中启动通知。

用例

让我们举一个拥有“x”个粉丝的 Instagram 名人影响者的例子。因此,当名人添加帖子的那一刻,所有关注者都会收到通知。

让我们使用 Observer Design Pattern 实现上述用例。

学习目标

  • 如何使用观察者设计模式进行编码?

开始

根据用例,第一个 API 实现一个接口,其中包含名人可以执行的操作。它被称为 “主题”。

public interface ICelebrityInstagram{  
 string FullName { get; }  
 string Post { get; set; }  
 void Notify(string post);  
 void AddFollower(IFollower fan);  
 void RemoveFollower(IFollower fan);  
}

Subject 包含以下成员函数。

  • 通知: 通知所有关注者。
  • AddFollower 中: 向名人列表添加新的关注者。
  • RemoveFollower 的 RemoveFollower 中: 从名人列表中删除关注者。

现在实现观察者 “IFollower” 接口,其中包含用于通知的 “Update” 成员函数。

public interface IFollower{  
 void Update(ICelebrityInstagram celebrityInstagram);  
}

最后,是时候为 “Subject” 和 “Observer” 实现 “Concrete Implementation” 了。

名为 “Follower.cs” 的 ConcreteObserver

它提供了Update成员函数的实现,该函数将名人姓名和帖子输出到控制台。

public class Follower : IFollower  
{  
    public void Update(ICelebrityInstagram celebrityInstagram)  
    {  
        Console.WriteLine($"Follower notified. Post of {celebrityInstagram.FullName}: " +  
            $"{celebrityInstagram.Post}");  
    }  
}

名为 “Sukhpinder.cs”

public class Sukhpinder : ICelebrityInstagram  
{  
    private readonly List<IFollower> _posts = new List<IFollower>();  
    private string _post;  
    public string FullName => "Sukhpinder Singh";  
  
    public string Post {  
        get { return _post; }  
        set  
        {  
            Notify(value);  
        }  
    }  
    public void AddFollower(IFollower follower)  
    {  
        _posts.Add(follower);  
    }  
    public void Notify(string post)  
    {  
        _post = post;  
        foreach (var item in _posts)  
        {  
            item.Update(this);  
        }  
    }  
    public void RemoveFollower(IFollower follower)  
    {  
        _posts.Remove(follower);  
    }  
}

如何使用观察者模式?

以下用例显示,每当执行以下语句时,都会为每个 follower 触发 update 方法,即每个 follower 对象都会收到来自“Sukhpinder”的新帖子的通知。sukhpinder.Post = “I love design patterns.”;

static void Main(string[] args)  
{  
    var sukhpinder = new Sukhpinder();  
  
    var firstFan = new Follower();  
    var secondFan = new Follower();  
    sukhpinder.AddFollower(firstFan);  
    sukhpinder.AddFollower(secondFan);  
    sukhpinder.Post = "I love design patterns.";  
    Console.Read();  
}

输出

高级属性模式 C# 8.0

本文介绍了模式匹配如何提供一种有效的方法来利用和处理不属于主系统的表单中的数据。

让我们开始吧

让我们以 Toll Calculator 为例,看看模式匹配如何帮助为此编写算法。

整篇文章中使用的实体类

public class Car  
  {  
      public int PassengerCount { get; set; }  
  }  
  public class DeliveryTruck  
  {  
      public int Weight { get; set; }  
  }  
  public class Taxi  
  {  
      public int Fare { get; set; }  
  }  
  public class Bus  
  {  
      public int Capacity { get; set; }  
      public int RidersCount { get; set; }  
  }

示例 1:根据以下条件计算通行费:

  • 如果车辆是 Car => 100 Rs
  • 如果车辆是 DeliveryTruck => 200 卢比
  • 如果车辆是公共汽车 => 150 卢比
  • 如果车辆是出租车 => 120 卢比

具有新 switch 语法的模式匹配程序

如果车辆类型与车辆类型匹配,则返回100辆汽车,以此类推。请注意,null & {} 是对象类型的默认情况。

此外,“_” 可用于对默认场景进行编程。请参阅新的 switch 语法。

这是一种更加清晰和高效的编码方式,并且还推荐在switch语法中使用单字母变量名称。

public static int TollFare(Object vehicleType) => vehicleType switch  
{  
 Car c => 100,  
 DeliveryTruck d => 200,  
 Bus b => 150,  
 Taxi t => 120,  
 null => 0,  
 { } => 0  
};

测试上述程序

从控制台应用程序的角度测试示例。下面的代码说明了如何从 main 方法调用上述模式匹配函数。

var car = new Car();  
var taxi = new Taxi();  
var bus = new Bus();  
var truck = new DeliveryTruck();Console.WriteLine($"The toll for a car is {TollFare(car)}");  
Console.WriteLine($"The toll for a taxi is {TollFare(taxi)}");  
Console.WriteLine($"The toll for a bus is {TollFare(bus)}");  
Console.WriteLine($"The toll for a truck is {TollFare(truck)}");

控制台输出

The toll for a car is 100  
The toll for a taxi is 120  
The toll for a bus is 150  
The toll for a truck is 200

示例 2: 根据车辆类型添加占用价格

  • 有“否”乘客的汽车和出租车额外支付10卢比。
  • 两名乘客的汽车和出租车可享受10卢比的折扣。
  • 三人或以上乘客的汽车和出租车可享受20卢比的折扣。
  • 乘客人数少于 50% 的公交车需额外支付 30 卢比。
  • 载有 90% 以上乘客的公共汽车可享受 40 卢比的折扣。
  • 超过 5000 磅的卡车需额外收费 100 卢比。
  • 3000 磅以下的轻型卡车,可享受 20 卢比的折扣。

Pattern Matching 开关

参考具有单个和多个属性类的模式匹配语法。链接

模式匹配 — Car 实体

Car { PassengerCount: 0 } => 100 + 10,  
Car { PassengerCount: 1 } => 100,  
Car { PassengerCount: 2 } => 100 - 10,  
Car c => 100 - 20,

模式匹配 — 出租车实体

Taxi {Fare:0 }=>100+10,  
Taxi { Fare: 1 } => 100,  
Taxi { Fare: 2 } => 100 - 10,  
Taxi t => 100 - 20,

模式匹配 — 总线实体

Bus b when ((double)b.RidersCount / (double)b.Capacity) \< 0.50 => 150 + 30,Bus b when ((double)b.RidersCount / (double)b.Capacity) > 0.90 => 150 - 40,Bus b => 150,

模式匹配 — 送货卡车实体

DeliveryTruck t when (t.Weight > 5000) => 200 + 100,  
DeliveryTruck t when (t.Weight \< 3000) => 200 - 20,  
DeliveryTruck t => 200,

组合所有实体

下面的示例突出了模式匹配的优点:模式分支是按顺序编译的。编译器还会对无法访问的代码发出警告。

public static int OccupancyTypeTollFare(Object vehicleType) => vehicleType switch  
  {  
      Car { PassengerCount: 0 } => 100 + 10,  
      Car { PassengerCount: 1 } => 100,  
      Car { PassengerCount: 2 } => 100 - 10,  
      Car c => 100 - 20,  
      Taxi { Fare: 0 } => 100 + 10,  
      Taxi { Fare: 1 } => 100,  
      Taxi { Fare: 2 } => 100 - 10,  
      Taxi t => 100 - 20,  
      Bus b when ((double)b.RidersCount / (double)b.Capacity) \< 0.50 => 150 + 30,  
      Bus b when ((double)b.RidersCount / (double)b.Capacity) > 0.90 => 150 - 40,  
      Bus b => 150,  
      DeliveryTruck t when (t.Weight > 5000) => 200 + 100,  
      DeliveryTruck t when (t.Weight \< 3000) => 200 - 20,  
      DeliveryTruck t => 200,  
      null => 0,  
      { } => 0,  
  };

测试上述程序

从控制台应用程序的角度测试示例。下面的代码说明了如何从 main 方法调用上述模式匹配函数。

var car1 = new Car{ PassengerCount=2};  
var taxi1 = new Taxi { Fare = 0 };  
var bus1 = new Bus { Capacity = 100, RidersCount = 30 };  
var truck1 = new DeliveryTruck { Weight = 30000 };Console.WriteLine($"The toll for a car is {OccupancyTypeTollFare(car1)}");  
Console.WriteLine($"The toll for a taxi is {OccupancyTypeTollFare(taxi1)}");  
Console.WriteLine($"The toll for a bus is {OccupancyTypeTollFare(bus1)}");  
Console.WriteLine($"The toll for a truck is {OccupancyTypeTollFare(truck1)}");

控制台输出

The toll for a car is 90  
The toll for a taxi is 110  
The toll for a bus is 180  
The toll for a truck is 300

“模式匹配使代码更具可读性,并在您无法将代码添加到类时提供面向对象技术的替代方案。”

设计模式 — 单例

Gang of Four — 单例设计模式确保特定类只有一个实例/对象和一个全局访问点。

学习目标

  • 如何使用单例设计模式进行编码?

开始

单例类用于消除特定类的多个对象的实例化。

public class SingletonExample  
{  
    private string Name { get; set; } = "Hello from singleton";  
    private static SingletonExample _instance;  
    public static SingletonExample Instance  
    {  
        get  
        {  
            if (_instance == null)  
            {  
                _instance = new SingletonExample();  
            }  
            return _instance;  
        }  
    }  
    public SingletonExample()  
    {  
    }  
    public string GetName() => Name;  
}

故障

  1. 迭代 1 意味着将仅创建实例。_instance==null
  2. 迭代 2,与现在一样 因此将返回以前创建的实例。_intance !=null

使用 Console 应用程序进行测试

让我们调用两次 singleton 类,并将返回的实例分配给两个不同的变量。最后,使用该函数检查两个对象是否相等。Object.Equals

static void Main(string[] args)  
{  
    var response = SingletonExample.Instance;  
    Console.WriteLine(response);  
  
    var response1 = SingletonExample.Instance;  
    Console.WriteLine(response1);  
    Console.WriteLine(Object.Equals(response1, response));  
}
  • 如果返回 true,则表示每次都会生成一个实例。
  • 如果返回 false,则表示该类未遵循单例模式。

输出

控制台输出返回 true;祝贺。您已成功实现 Singleton Pattern。

线程安全

上面的类被称为 singleton 类,但目前,它不是线程安全的。在多线程环境中,两个线程可以同时 hit statement,我们最终将拥有一个单例类的多个实例。if (_instance == null)

更安全线程的一种方法是使用锁机制,另一种方法是使用只读实例以获得更简洁、更高效的方法。

public class ThreadSafeSingleton  
{  
    private static readonly ThreadSafeSingleton _instance = new ThreadSafeSingleton();  
    public static ThreadSafeSingleton Instance  
    {  
        get  
        {  
            return _instance;  
        }  
    }  
    public ThreadSafeSingleton()  
    {  
    }  
}

源代码获取:公众号回复消息【code:36020

相关代码下载地址
重要提示!:取消关注公众号后将无法再启用回复功能,不支持解封!
第一步:微信扫码关键公众号“架构师老卢”
第二步:在公众号聊天框发送code:36020,如:code:36020 获取下载地址
第三步:恭喜你,快去下载你想要的资源吧
相关留言评论
昵称:
邮箱:
阅读排行