策略模式实现搜索功能

发布于:2024-09-18 ⋅ 阅读:(137) ⋅ 点赞:(0)
概念:

策略模式是一种行为设计模式,用于定义一系列算法,将他们封装起来,并使他们可以互相替换。使用策略模式可以让代码更加灵活,且易于扩展和维护

背景:

假设你有一个功能需要多种不同的算法或行为实现(如不同的排序方式、不同的支付方式、不同的搜索方式等),这些行为是相似的。但是在细节上有所不同。

核心:

将这些可变的行为封装为不同的策略累,并定义一个接口来规范这些策略的实现。这样就可以在运行时动态切换策略,而不需要修改客户端的代码

用途:

1、替换不同的算法:可以根据需要动态的选择不同的算法或实现。比如不同的折扣策略,不同的支付方式

2、简化条件语句:用策略模式可以替换大量的if-else语句

3、提高可扩展性:新增一种行为时,只需要添加一个新的策略类,而不需要修改现有的代码

基本结构:

1、策略接口(Strategy Interface):定义所有策略类必须实现的方法。

2、具体策略类(Concrete Strategy):每个类实现具体的算法或行为。

3、上下文类(Context):持有一个策略对象并调用策略的方法。

示例:

假设你有一个电商平台,根据用户的等级(普通用户、会员、VIP)给予不同的折扣。我们可以使用策略模式来实现不同的折扣逻辑。

1、定义策略接口

// 策略接口,定义计算折扣的方法
public interface IDiscountStrategy
{
    decimal CalculateDiscount(decimal price);
}

2、实现具体的策略类

// 普通用户的折扣策略:无折扣
public class NoDiscountStrategy : IDiscountStrategy
{
    public decimal CalculateDiscount(decimal price)
    {
        return price; // 无折扣
    }
}

// 会员的折扣策略:10% 折扣
public class MemberDiscountStrategy : IDiscountStrategy
{
    public decimal CalculateDiscount(decimal price)
    {
        return price * 0.9m; // 10% 折扣
    }
}

// VIP 的折扣策略:20% 折扣
public class VIPDiscountStrategy : IDiscountStrategy
{
    public decimal CalculateDiscount(decimal price)
    {
        return price * 0.8m; // 20% 折扣
    }
}

3、创建上下文

// 上下文类,用于选择和执行策略
public class ShoppingCart
{
    private IDiscountStrategy _discountStrategy;

    // 通过构造函数设置策略
    public ShoppingCart(IDiscountStrategy discountStrategy)
    {
        _discountStrategy = discountStrategy;
    }

    // 计算折扣后的价格
    public decimal CalculateTotalPrice(decimal price)
    {
        return _discountStrategy.CalculateDiscount(price);
    }
}

4、使用策略模式

public class Program
{
    public static void Main(string[] args)
    {
        decimal originalPrice = 100m; // 商品的原价

        // 普通用户
        IDiscountStrategy noDiscount = new NoDiscountStrategy();
        ShoppingCart cartForNormalUser = new ShoppingCart(noDiscount);
        Console.WriteLine($"普通用户的价格: {cartForNormalUser.CalculateTotalPrice(originalPrice)}");

        // 会员用户
        IDiscountStrategy memberDiscount = new MemberDiscountStrategy();
        ShoppingCart cartForMember = new ShoppingCart(memberDiscount);
        Console.WriteLine($"会员用户的价格: {cartForMember.CalculateTotalPrice(originalPrice)}");

        // VIP 用户
        IDiscountStrategy vipDiscount = new VIPDiscountStrategy();
        ShoppingCart cartForVIP = new ShoppingCart(vipDiscount);
        Console.WriteLine($"VIP 用户的价格: {cartForVIP.CalculateTotalPrice(originalPrice)}");
    }
}

运行结果:

普通用户的价格: 100
会员用户的价格: 90
VIP 用户的价格: 80

理解了策略模式后,开始设计搜索功能。

1、定义策略接口

        public interface ISearchStrategy
        {
            List<PatientData> ExecuteSearch();
        }

2、实现具体的策略类,由于搜索条件有可能同时满足,所以定义组合策略类

    /// <summary>
    /// 日期搜索
    /// </summary>
    public class DateSearchStrategy : ISearchStrategy
    {
        private DateTime _date1, _date2;
        public DateSearchStrategy(DateTime date1, DateTime date2)
        {
            _date1 = date1.Date;
            _date2 = date2.Date;
        }

        public List<PatientData> ExecuteSearch()
        {
            return T_PatientDataAccess.GetPatientArchives(startDate:_date1,endDate: _date2);
        }
    }

    /// <summary>
    /// 病人姓名搜索
    /// </summary>
    public class PatientNameSearchStrategy : ISearchStrategy
    {
        private string _name;
        public PatientNameSearchStrategy(string name)
        {
            _name = name;
        }

        public List<PatientData> ExecuteSearch()
        {
            return T_PatientDataAccess.GetPatientArchives(patientName:_name);
        }
    }
    /// <summary>
    /// 医生姓名搜索
    /// </summary>
    public class DoctorNameSearchStrategy : ISearchStrategy
    {
        private string _name;
        public DoctorNameSearchStrategy(string name)
        {
            _name = name;
        }

        public List<PatientData> ExecuteSearch()
        {
            return T_PatientDataAccess.GetPatientArchives(patientName: _name);
        }
    }

    /// <summary>
    /// 组合搜索
    /// </summary>
    public class CompositeSearchStrategy : ISearchStrategy
    {
        private readonly List<ISearchStrategy> _strategies = new List<ISearchStrategy>();

        public void AddStrategy(ISearchStrategy strategy)
        {
            _strategies.Add(strategy);
        }

        public List<PatientData> ExecuteSearch()
        {
            List<PatientData> datas = new List<PatientData>();

            // 如果没有条件,返回所有数据
            if (_strategies.Count == 0)
            {
                return datas;
            }
         
            // 逐步过滤数据
            foreach (var strategy in _strategies)
            {
                if (datas.Count == 0)
                {
                    datas = strategy.ExecuteSearch();     //第一条搜索
                }
                else
                {
                    datas = datas.Where(p1 => strategy.ExecuteSearch().Any(p2 => p1.inspectNumber == p2.inspectNumber)).ToList();   //求交集
                }

            }
            return datas;
        }

3、定义上下文

public class B_T_patientSearchService
    {
        /// <summary>
        /// 搜索服务
        /// </summary>
        /// <param name="startDate">开始日期</param>
        /// <param name="endDate">结束日期</param>
        /// <param name="patientName">病人名字</param>
        /// <param name="doctorName">医生姓名</param>
        /// <returns></returns>
        public List<PatientData> Search(string startDate, string endDate, string patientName, string doctorName)
        {
            var searchStrategy = new CompositeSearchStrategy();

            if (!string.IsNullOrWhiteSpace(startDate) && !string.IsNullOrWhiteSpace(endDate))
            { 
                searchStrategy.AddStrategy(new DateSearchStrategy(DateTime.Parse(startDate),DateTime.Parse(endDate)));
            }

            if (!string.IsNullOrWhiteSpace(patientName))
            {
                searchStrategy.AddStrategy(new PatientNameSearchStrategy(patientName));
            }

            if (!string.IsNullOrWhiteSpace(doctorName))
            {
                searchStrategy.AddStrategy(new DoctorNameSearchStrategy(doctorName));
            }

            // 传入所有数据,依次应用过滤策略
            return searchStrategy.ExecuteSearch();
        }
    }

4、狠狠的使用它

        /// <summary>
        /// 搜索功能实现
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSearch_Click(object sender, EventArgs e)
        {
            PerformSearch(tbStartDate.Text, tbEndDate.Text, cbPatientName.Text, cbDoctorName.Text);
            ControlStatus(false);
        }


        /// <summary>
        /// 执行查询并绑定数据
        /// </summary>
        /// <param name="startDate">开始日期</param>
        /// <param name="endDate">结束日期</param>
        /// <param name="patientName">患者姓名</param>
        /// <param name="doctorName">医生姓名</param>
        private void PerformSearch(string startDate, string endDate, string patientName, string doctorName)
        {
            var searchService = new B_T_patientSearchService();
            var list = searchService.Search(startDate, endDate, patientName, doctorName);
            DataTable dataTable = new DataTable();

            if (list != null && list.Count > 0)
            {
                dataTable = ConvertToDataTable(list);
                tempTable = dataTable; 
                dataGridView1.AutoGenerateColumns = false;     // 固定标题栏
                dataGridView1.DataSource = tempTable;
                // 绑定数据
                LoadT_PatientArchivesManageToText();
            }
            else
            {
                dataGridView1.DataSource = dataTable;
            }

            lblTotal.Text = "查询总数:" + dataGridView1.RowCount;
        }


网站公告

今日签到

点亮在社区的每一天
去签到