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

如何遵循开闭原则扩展耦合的House与Window模型?

面向开闭原则的Window扩展方案选型

现有系统模型

中等规模系统中,以下模型代码已被多处引用:

public class House
{
    public House(IEnumerable<Window> windows)
    {
        Windows = windows;
    }

    public IEnumerable<Window> Windows { get; private set; }
}

public class Window
{
    public Window(string brand, int height, int width)
    {
        Brand = brand;
        Height = height;
        Width = width;
    }

    public string Brand { get; private set; }
    public int Height { get; private set; }
    public int Width { get; private set; }
}

新增需求

系统部分模块需要判断Window是否具备SolarResistant(防紫外线)属性,但其他模块无需关心该属性。

已尝试的扩展方案及问题分析

方案1:继承Window实现子类

通过继承Window新增带IsSolarResistant属性的子类:

public class WindowMaybeSolarResistant : Window
{
    public WindowMaybeSolarResistant(string brand, int height, int width, bool isSolarResistant) : base(brand, height, width)
    {
        IsSolarResistant = isSolarResistant;
    }

    public bool IsSolarResistant { get; private set; }
}

问题:House类与Window高度耦合,系统中普遍默认House包含的是Window类型实例,子类无法直接替换使用。

方案2:为Window新增构造函数

直接修改Window类,新增带IsSolarResistant参数的构造函数:

public class Window : IWindow
{
    public Window(string brand, int height, int width)
    {
        Brand = brand;
        Height = height;
        Width = width;
        IsSolarResistant = false;  // 存在实际为true的窗口被误设为false的风险,容易误用构造函数
    }

    public Window(string brand, int height, int width, bool isSolarResistant)
    {
        Brand = brand;
        Height = height;
        Width = width;
        IsSolarResistant = isSolarResistant;
    }

    public string Brand { get; private set; }
    public int Height { get; private set; }
    public int Width { get; private set; }
    public bool IsSolarResistant { get; private set; }
}

问题:存在构造函数误用风险,且直接修改原有类违反开闭原则。

方案3:为House引入泛型与接口

定义IWindow抽象接口,将House改为泛型类:

public interface IWindow
{ 
    public string Brand { get;  }
    public int Height { get;  }
    public int Width { get;  }
}

public class House<TWindow> where TWindow : IWindow
{
    public House(IEnumerable<TWindow> windows)
    {
        Windows = windows;
    }

    public IEnumerable<TWindow> Windows { get; private set; }
}

优势:既保证了Window的基础属性约束,又为后续扩展预留了空间;完全符合开闭原则,无需修改原有Window和House的核心逻辑,只需新增实现IWindow的扩展类即可。

方案4:继承House类

通过继承House类,重写Windows属性类型:

public class HouseCouldHaveSolarWindows : House
{
    public HouseCouldHaveSolarWindows(IEnumerable<WindowMaybeSolarResistant> windows) : base(windows)
    {
    }

    public new IEnumerable<WindowMaybeSolarResistant> Windows { get; private set; }
}

问题:随着扩展需求增多,会导致类膨胀失控,维护成本急剧上升。

最佳方案推荐

方案3是最符合开闭原则的实现方式,理由如下:

  1. 通过IWindow接口抽象窗口核心属性,彻底解耦House与具体Window类型的依赖;
  2. 原有Window类实现IWindow接口,无需修改原有业务逻辑,保证对修改关闭;
  3. 当需要新增SolarResistant属性时,只需新增实现IWindow的扩展类,原有模块不受影响,符合对扩展开放的要求;
  4. 泛型House<TWindow>可以适配任意实现IWindow的窗口类型,避免了类膨胀问题。

扩展实现示例

新增带防紫外线属性的窗口类:

public class SolarResistantWindow : IWindow
{
    public SolarResistantWindow(string brand, int height, int width, bool isSolarResistant)
    {
        Brand = brand;
        Height = height;
        Width = width;
        IsSolarResistant = isSolarResistant;
    }

    public string Brand { get; private set; }
    public int Height { get; private set; }
    public int Width { get; private set; }
    public bool IsSolarResistant { get; private set; }
}

使用时,需要该属性的模块可以直接使用House<SolarResistantWindow>,无需关心该属性的模块仍可使用原有House<Window>,完全隔离不同需求的模块。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 01:54:54