C# 使用抽象工厂模式实现花园规划系统的设计与实现

发布于:2025-08-29 ⋅ 阅读:(15) ⋅ 点赞:(0)

在软件工程中,设计模式是解决复杂问题的重要工具。本文将深入探讨如何使用抽象工厂模式(Abstract Factory Pattern)实现一个花园规划系统。我们将通过C#语言,结合面向对象的思想,构建一个结构清晰、扩展性强的花园规划应用程序。


一、抽象工厂模式简介

抽象工厂模式是一种创建型设计模式,用于创建一组相关或依赖对象的家族,而无需指定其具体类。它适用于需要统一管理多个产品系列的场景。

在本例中,我们面对的是三种不同类型的花园:

  1. 蔬菜型花园(VeggieGarden)
  2. 多年生植物花园(PerennialGarden)
  3. 一年生植物花园(AnnualGarden)

每种花园都需要在三个不同区域种植植物:中央、边缘和阴凉区域。通过抽象工厂模式,我们可以将这些植物的创建逻辑封装在各自的工厂中,使得系统更易于维护和扩展。


二、系统核心类设计

1. Garden 抽象工厂类

Garden 作为抽象工厂的基类,定义了创建植物对象的接口,并封装了绘制植物的逻辑。

public class Garden
{
    protected Plant center, shade, border;
    protected bool showCenter, showShade, showBorder;
 
    public void setCenter() { showCenter = true; }
    public void setBorder() { showBorder = true; }
    public void setShade() { showShade = true; }
 
    public void draw(Graphics g)
    {
        if (showCenter) center.draw(g, 100, 100);
        if (showShade) shade.draw(g, 10, 50);
        if (showBorder) border.draw(g, 50, 100);
    }
}
  • 功能分析:该类定义了三种植物对象(中心、边缘、阴凉)及其显示状态,通过 draw 方法控制图形绘制。
  • 设计意图:隐藏具体植物的创建逻辑,只暴露使用接口。

2. Plant

Plant 是所有植物的基类,负责绘制植物名称。

public class Plant
{
    private string name;
    private Brush br;
    private Font font;
 
    public Plant(string pname)
    {
        name = pname;
        font = new Font("Arial", 12);
        br = new SolidBrush(Color.Black);
    }
 
    public void draw(Graphics g, int x, int y)
    {
        g.DrawString(name, font, br, x, y);
    }
}
  • 功能分析:封装植物的图形绘制逻辑。
  • 可扩展性:未来可扩展为支持图像、颜色变化等。

3. 具体工厂类(如 VeggieGarden

每个具体花园类继承自 Garden,并实现具体的植物创建逻辑:

public class VeggieGarden : Garden
{
    public VeggieGarden()
    {
        shade = new Plant("Broccoli");
        border = new Plant("Peas");
        center = new Plant("Corn");
    }
}
  • 设计意图:通过继承抽象工厂,提供特定类型花园的植物配置。
  • 灵活性:新增花园类型时,只需继承并覆写构造函数即可。

三、图形界面与事件处理

1. 自定义 GardenPic 控件

为了在界面中绘制花园,我们继承 PictureBox 并实现自定义绘制逻辑:

public class GdPic : System.Windows.Forms.PictureBox
{
    private Garden gden;
 
    public void setGarden(Garden garden)
    {
        gden = garden;
        this.Refresh();
    }
 
    protected override void OnPaint(PaintEventArgs pe)
    {
        base.OnPaint(pe);
        Graphics g = pe.Graphics;
        g.FillEllipse(Brushes.LightGray, 5, 5, 100, 100);
        if (gden != null)
            gden.draw(g);
    }
}
  • 功能分析:绘制圆形表示阴影区域,并调用当前花园的 draw 方法绘制植物名称。
  • 设计意图:解耦UI绘制与数据模型,提高可维护性。

2. 单选按钮与复选框事件处理

通过事件驱动机制,实现用户交互与数据更新的同步:

private void opAnnual_CheckedChanged(object sender, EventArgs e)
{
    setGarden(new AnnualGarden());
}
 
private void setGarden(Garden gd)
{
    garden = gd;
    gdPic1.setGarden(gd);
    ckCenter.Checked = false;
    ckBorder.Checked = false;
    ckShade.Checked = false;
}
  • 功能分析:切换花园类型时重建植物配置并刷新界面。
  • 设计意图:保持界面状态与数据模型的一致性。

四、系统扩展与可维护性

1. 添加新花园类型

抽象工厂模式的一大优势是易于扩展。例如,添加 WildFlowerGarden

public class WildFlowerGarden : Garden 
{
    public WildFlowerGarden()
    {
        shade = new Plant("Fern");
        border = new Plant("Daisy");
        center = new Plant("Sunflower");
    }
}
  • 修改点:只需新增类,并在UI中添加对应的单选按钮即可。
  • 影响分析:不影响已有类,符合开闭原则。

2. 处理差异化的植物行为

若某类花园具有特有功能(如 BonsaiGardenWateringFrequency 方法),可通过以下方式处理:

  • 方案一:在 Garden 基类中定义所有可能的方法(即使为空实现)
  • 方案二:定义新的接口 IWatering,并在需要的子类中实现
public interface IWatering 
{
    int WateringFrequency { get; }
}
 
public class BonsaiGarden : Garden, IWatering 
{
    public int WateringFrequency => 3;
}
  • 设计原则:遵循接口隔离原则(ISP),避免类污染。

五、设计模式的优势与局限性

优势

优势 说明
封装具体类 客户端无需了解具体类名,只需使用工厂接口
统一产品族 确保一组相关类的使用一致性,防止混用
扩展性强 新增产品族只需添加新工厂类,无需修改现有代码

局限

局限 说明
扩展产品种类困难 抽象工厂接口一旦确定,新增产品种类需修改接口
类型绑定紧密 不同产品族之间结构相似性高,不适合结构差异大的情况

六、总结与思考

通过抽象工厂模式,我们实现了一个结构清晰、易于扩展的花园规划系统。该系统不仅满足了当前三种花园类型的需求,还具备良好的可维护性和可读性。

在实际项目中,抽象工厂模式常用于以下场景:

  • UI组件库(如跨平台界面控件)
  • 游戏中的角色与装备系统
  • 多数据库适配器

未来可以进一步探索结合策略模式与装饰器模式,实现更灵活的植物配置与交互体验。


结语:抽象工厂不仅仅是代码的组织方式,更是一种思维方式。它教会我们如何在变化中保持系统的稳定,在复杂中寻找结构的统一。希望本文能为你的设计模式之旅带来启发。



网站公告

今日签到

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