装饰器模式
是一种结构型设计模式
,它允许在运行时动态地给一个对象添加职责,而不需要修改对象的结构。
装饰器模式通过创建一个包装对象来包裹真实的对象,从而在不改变对象接口的情况下增加新的行为或责任。
案例 1:日志记录器
场景描述
在日志记录系统中,我们可能需要在不同的地方记录日志,例如控制台、文件、数据库
等。使用装饰器模式可以动态地添加不同的记录方式,而不需要修改原有的日志记录逻辑。
代码实现
using System;
using System.IO;// 抽象的日志记录器接口
public interface ILogger
{void Log(string message);
}// 具体的日志记录器实现
public class ConsoleLogger : ILogger
{public void Log(string message){Console.WriteLine($"Console: {message}");}
}// 装饰器基类
public abstract class LoggerDecorator : ILogger
{protected readonly ILogger _logger;public LoggerDecorator(ILogger logger){_logger = logger;}public virtual void Log(string message){_logger.Log(message);}
}// 文件日志记录器装饰器
public class FileLoggerDecorator : LoggerDecorator
{public FileLoggerDecorator(ILogger logger) : base(logger) { }public override void Log(string message){base.Log(message);using (StreamWriter writer = new StreamWriter("log.txt", true)){writer.WriteLine($"File: {message}");}}
}// 数据库日志记录器装饰器
public class DatabaseLoggerDecorator : LoggerDecorator
{public DatabaseLoggerDecorator(ILogger logger) : base(logger) { }public override void Log(string message){base.Log(message);// 假设这里有一个数据库连接Console.WriteLine($"Database: {message}");}
}// 使用示例
public class Program
{public static void Main(){ILogger logger = new ConsoleLogger();logger = new FileLoggerDecorator(logger);logger = new DatabaseLoggerDecorator(logger);logger.Log("This is a log message.");// 输出:// Console: This is a log message.// File: This is a log message.// Database: This is a log message.}
}
类型图:
代码解析
- ILogger 接口:定义了日志记录的基本方法。
- ConsoleLogger 类:实现了 ILogger 接口,将日志记录到控制台。
- LoggerDecorator 类:装饰器基类,包含一个 ILogger 对象,并提供了默认的 Log 方法。
- FileLoggerDecorator 类:具体的装饰器,将日志记录到文件。
- DatabaseLoggerDecorator 类:具体的装饰器,将日志记录到数据库。
- 客户端代码:创建日志记录器,并通过装饰器动态地添加不同的记录方式。
案例 2:咖啡店的饮料装饰
场景描述
在一家咖啡店中,顾客可以选择不同的基础饮料(如咖啡、茶),并可以添加不同的调料(如糖、奶)。使用装饰器模式可以动态地添加调料,而不需要为每一种组合创建一个新的类。
代码实现
using System;// 抽象的饮料接口
public interface IBeverage
{string Description { get; }double Cost { get; }
}// 具体的饮料实现
public class Coffee : IBeverage
{public string Description => "Coffee";public double Cost => 2.00;
}public class Tea : IBeverage
{public string Description => "Tea";public double Cost => 1.50;
}// 装饰器基类
public abstract class BeverageDecorator : IBeverage
{protected readonly IBeverage _beverage;public BeverageDecorator(IBeverage beverage){_beverage = beverage;}public virtual string Description => _beverage.Description;public virtual double Cost => _beverage.Cost;
}// 添加糖的装饰器
public class SugarDecorator : BeverageDecorator
{public SugarDecorator(IBeverage beverage) : base(beverage) { }public override string Description => $"{_beverage.Description}, Sugar";public override double Cost => _beverage.Cost + 0.50;
}// 添加奶的装饰器
public class MilkDecorator : BeverageDecorator
{public MilkDecorator(IBeverage beverage) : base(beverage) { }public override string Description => $"{_beverage.Description}, Milk";public override double Cost => _beverage.Cost + 0.75;
}// 使用示例
public class Program
{public static void Main(){IBeverage coffee = new Coffee();coffee = new SugarDecorator(coffee);coffee = new MilkDecorator(coffee);Console.WriteLine($"{coffee.Description}: ${coffee.Cost}");// 输出: Coffee, Sugar, Milk: $3.25}
}
类型图:
代码解析
- IBeverage 接口:定义了饮料的基本属性和方法。
- Coffee 类 和 Tea 类:具体的饮料实现。
- BeverageDecorator 类:装饰器基类,包含一个 IBeverage 对象,并提供了默认的 Description 和 Cost 方法。
- SugarDecorator 类 和 MilkDecorator 类:具体的装饰器,分别添加糖和奶。
- 客户端代码:创建饮料,并通过装饰器动态地添加调料。
案例 3:用户权限管理
场景描述
在用户权限管理系统中,用户可能有不同的角色(如普通用户、管理员),并且每个角色可能有额外的权限(如审核、删除)。使用装饰器模式可以动态地为用户添加不同的权限,而不需要为每一种角色创建一个新的类。
代码实现
using System;
using System.Collections.Generic;// 抽象的用户接口
public interface IUser
{string Name { get; }List<string> Permissions { get; }void GrantPermission(string permission);
}// 具体的用户实现
public class BasicUser : IUser
{public string Name { get; }public List<string> Permissions { get; } = new List<string>();public BasicUser(string name){Name = name;}public void GrantPermission(string permission){Permissions.Add(permission);}
}// 装饰器基类
public abstract class UserDecorator : IUser
{protected readonly IUser _user;public UserDecorator(IUser user){_user = user;}public virtual string Name => _user.Name;public virtual List<string> Permissions => _user.Permissions;public virtual void GrantPermission(string permission) => _user.GrantPermission(permission);
}// 管理员装饰器
public class AdminDecorator : UserDecorator
{public AdminDecorator(IUser user) : base(user) { }public override void GrantPermission(string permission){base.GrantPermission(permission);if (!Permissions.Contains("Admin")){Permissions.Add("Admin");}}
}// 审核员装饰器
public class AuditorDecorator : UserDecorator
{public AuditorDecorator(IUser user) : base(user) { }public override void GrantPermission(string permission){base.GrantPermission(permission);if (!Permissions.Contains("Audit")){Permissions.Add("Audit");}}
}// 使用示例
public class Program
{public static void Main(){IUser user = new BasicUser("John Doe");user = new AdminDecorator(user);user = new AuditorDecorator(user);user.GrantPermission("Read");user.GrantPermission("Write");Console.WriteLine($"{user.Name} has permissions: {string.Join(", ", user.Permissions)}");// 输出: John Doe has permissions: Read, Write, Admin, Audit}
}
类型图:
代码解析
- IUser 接口:定义了用户的属性和方法。
- BasicUser 类:具体的用户实现,包含基本的权限管理。
- UserDecorator 类:装饰器基类,包含一个 IUser 对象,并提供了默认的属性和方法。
- AdminDecorator 类 和 AuditorDecorator 类:具体的装饰器,分别为用户添加管理员和审核员权限。
- 客户端代码:创建用户,并通过装饰器动态地添加不同的权限。
优点
- 灵活性:可以在运行时动态地添加或移除职责,增加了系统的灵活性。
- 扩展性:通过装饰器类可以轻松地扩展对象的功能,而不需要修改原有的类。
- 符合开闭原则:装饰器模式遵循开闭原则,即对扩展开放,对修改关闭。
缺点
- 类的数量增加:每个装饰器都是一个类,随着装饰器数量的增加,类的数量也会增加,可能导致系统复杂度上升。
- 调试困难:由于装饰器的嵌套层次可能较深,调试时可能会比较困难。
- 性能开销:每次调用装饰器的方法时都会有一定的性能开销,尤其是在多层装饰器的情况下。
通过以上三个案例,我们可以看到装饰器模式在实际开发中的应用及其优缺点。希望这些示例能帮助你更好地理解和应用装饰器模式。