You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

是否违反LSP后置条件规则?求符合Liskov替换原则的改造方案

Liskov替换原则(LSP)后置条件违规分析与改造方案

问题背景

根据LSP的后置条件规则:

LSP: 后置条件不能被弱化,只能被强化。

现有代码中:

  • 父类ProcessController的GetRunningProcess方法返回不包含application类型的进程集合(包含system和user类型)
  • 子类UserProcessController仅返回user类型的进程
  • 子类ApplicationProcessController仅返回application类型的进程

需要确认这两个子类是否存在弱化后置条件的情况,并给出符合LSP要求的改造方案。

原代码实现

public class ProcessController
{
    public virtual Dictionary<int, string> GetRunningProcess()
    {
        Dictionary<int, string> processes = new()
        {
            { 1, "system" },
            { 44, "system" },
            { 45, "user" },
            { 102, "user" },
            { 176, "user" },
            { 274, "application" },
            { 188, "application" }
        };
        return processes.Where(x => !x.Value.Equals("application")).ToDictionary();
    }
}

public class UserProcessController : ProcessController
{
    public override Dictionary<int, string> GetRunningProcess()
    {
        Dictionary<int, string> processes = new()
        {
            { 1, "system" },
            { 44, "system" },
            { 45, "user" },
            { 102, "user" },
            { 176, "user" },
            { 274, "application" },
            { 188, "application" }
        };
        Dictionary<int, string> userProcess = processes.Where(x => x.Value.Equals("user")).ToDictionary();
        return userProcess;
    }
}

public class ApplicationProcessController : ProcessController
{
    public override Dictionary<int, string> GetRunningProcess()
    {
        Dictionary<int, string> processes = new()
        {
            { 1, "system" },
            { 44, "system" },
            { 45, "user" },
            { 102, "user" },
            { 176, "user" },
            { 274, "application" },
            { 188, "application" }
        };
        Dictionary<int, string> userProcess = processes.Where(x => x.Value.Equals("application")).ToDictionary();
        return userProcess;
    }
}

违规分析

  1. UserProcessController 未违反LSP
    父类的后置条件是“返回的进程集合不包含application类型”,子类返回的user类型进程完全满足这个条件,并且额外增加了“仅包含user类型”的约束——这属于强化后置条件,符合LSP要求。

  2. ApplicationProcessController 违反LSP
    父类明确保证返回结果中没有application类型的进程,但子类直接返回了仅包含application类型的集合,完全破坏了父类的后置条件契约——这属于弱化后置条件,违反了LSP规则。

符合LSP的改造方案

核心思路是:避免让功能契约不同的类通过继承绑定,改用接口抽象或基于通用父类的扩展,确保每个类的契约清晰且符合父类/接口的约束。

方案1:使用接口分离

定义统一的进程检索接口,各个控制器独立实现接口,不存在继承关系,从根源上避免LSP冲突:

public interface IProcessRetriever
{
    Dictionary<int, string> GetRunningProcess();
}

public class NonApplicationProcessController : IProcessRetriever
{
    public Dictionary<int, string> GetRunningProcess()
    {
        var processes = ProcessHelper.GetAllProcesses();
        return processes.Where(x => !x.Value.Equals("application")).ToDictionary();
    }
}

public class UserProcessController : IProcessRetriever
{
    public Dictionary<int, string> GetRunningProcess()
    {
        var processes = ProcessHelper.GetAllProcesses();
        return processes.Where(x => x.Value.Equals("user")).ToDictionary();
    }
}

public class ApplicationProcessController : IProcessRetriever
{
    public Dictionary<int, string> GetRunningProcess()
    {
        var processes = ProcessHelper.GetAllProcesses();
        return processes.Where(x => x.Value.Equals("application")).ToDictionary();
    }
}

// 提取公共方法,避免代码重复
public static class ProcessHelper
{
    public static Dictionary<int, string> GetAllProcesses()
    {
        return new Dictionary<int, string>
        {
            { 1, "system" },
            { 44, "system" },
            { 45, "user" },
            { 102, "user" },
            { 176, "user" },
            { 274, "application" },
            { 188, "application" }
        };
    }
}

方案2:调整继承层级(若需保留继承)

将父类改为返回所有进程的通用基类,子类通过过滤实现各自的功能,此时父类的后置条件是“返回所有进程”,子类的过滤操作属于强化后置条件:

public class BaseProcessController
{
    protected virtual Dictionary<int, string> GetAllProcesses()
    {
        return new Dictionary<int, string>
        {
            { 1, "system" },
            { 44, "system" },
            { 45, "user" },
            { 102, "user" },
            { 176, "user" },
            { 274, "application" },
            { 188, "application" }
        };
    }

    public virtual Dictionary<int, string> GetRunningProcess()
    {
        return GetAllProcesses();
    }
}

public class NonApplicationProcessController : BaseProcessController
{
    public override Dictionary<int, string> GetRunningProcess()
    {
        var allProcesses = GetAllProcesses();
        return allProcesses.Where(x => !x.Value.Equals("application")).ToDictionary();
    }
}

public class UserProcessController : BaseProcessController
{
    public override Dictionary<int, string> GetRunningProcess()
    {
        var allProcesses = GetAllProcesses();
        return allProcesses.Where(x => x.Value.Equals("user")).ToDictionary();
    }
}

public class ApplicationProcessController : BaseProcessController
{
    public override Dictionary<int, string> GetRunningProcess()
    {
        var allProcesses = GetAllProcesses();
        return allProcesses.Where(x => x.Value.Equals("application")).ToDictionary();
    }
}

内容的提问来源于stack exchange,提问作者riki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 11:22:08