浅谈C#设计模式之开放封闭原则

yizhihongxing

浅谈C#设计模式之开放封闭原则

开放封闭原则(Open Closed Principle,OCP)是设计模式中非常重要的一条原则,它强调软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。换句话说,当需求发生变化时,我们应该添加新的代码而不是修改已有的代码。这样能够保证系统的稳定性和可扩展性。

开放封闭原则的核心思想

开放封闭原则的核心思想可归纳为两个方面:

  1. 对于扩展是开放的(Open for extension):当需要添加新功能时,应该尽可能使用增加代码的方式来实现,而不是修改原有的代码。这样做的好处是,添加新功能不会破坏原有的代码,从而保证了系统的稳定性。
  2. 对于修改是关闭的(Closed for modification):当需求变化需要修改代码时,应该尽可能少地去修改已有的代码,而是通过扩展的方式来实现。这样做的好处是,代码修改的范围越小,那么引入新的Bug的风险也就越小。

实现开放封闭原则的方法

实现开放封闭原则的方法有很多,下面列举了三种常用的方法:

  1. 利用接口实现扩展。即,定义好接口,对于不同的实现类或者子类,使用不同的具体实现来达到扩展的目的。在这种方法下,新增的代码是实现新接口,而原有的代码需要实现扩展接口。举个例子,我们开发了一个图形界面的软件,现在要支持多种图形界面主题。我们可以定义一个 ITheme 接口,然后实现多个不同的主题,使得软件支持不同的主题。
public interface ITheme
{
    void Show();
}

public class LightTheme : ITheme
{
    public void Show()
    {
        Console.WriteLine("显示浅色主题的窗口");
    }
}

public class DarkTheme : ITheme
{
    public void Show()
    {
        Console.WriteLine("显示深色主题的窗口");
    }
}
  1. 利用抽象类实现扩展。虽然抽象类和接口都是用于定义抽象类型的,但是抽象类具有一些接口所不具备的特性。在使用抽象类时,可以将一些公共的逻辑放在抽象类中,而将具体的逻辑放在具体实现中,便于扩展和修改。举个例子,在某个跨平台的游戏中,如果想要加入新的控制模块,使用抽象类便是一种不错的选择。
public abstract class AbstractPlayer
{
    public abstract void Play();
}

public class WindowsPlayer : AbstractPlayer
{
    public override void Play()
    {
        Console.WriteLine("使用Windows平台播放视频");
    }
}

public class LinuxPlayer : AbstractPlayer
{
    public override void Play()
    {
        Console.WriteLine("使用Linux平台播放视频");
    }
}
  1. 利用设计模式实现扩展。很多设计模式都是为了实现开放封闭原则而生的,如策略模式、工厂模式、观察者模式等。利用设计模式实现扩展时,可以更加灵活地实现功能的扩展,从而保证系统的稳定和可扩展性。

示例1

我们有一个商店系统,需要根据用户的不同等级实现不同的优惠。开发人员在初始设计中,已经定义了一个 IUser 接口,用于表示不同等级的用户。我们现在需要根据用户等级,给不同的用户打不同的折扣。根据开放封闭原则,我们需要利用扩展的方式来实现这个功能。我们可以定义一个 IDiscount 接口,然后实现多个不同的折扣策略,使得系统可以随着需求更改而扩展。

interface IUser {
    int Level { get; set; }
}

interface IDiscount {
    double Calculate(double price);
}

class NormalUser : IUser {
    public int Level { get => 1; set => throw new NotImplementedException(); }
}

class VIPUser : IUser {
    public int Level { get => 2; set => throw new NotImplementedException(); }
}

class SuperVIPUser : IUser {
    public int Level { get => 3; set => throw new NotImplementedException(); }
}

class NormalDiscount : IDiscount {
    public double Calculate(double price)
    {
        return price;
    }
}

class VIPDiscount : IDiscount {
    public double Calculate(double price)
    {
        return price * 0.9;
    }
}

class SuperVIPDiscount : IDiscount {
    public double Calculate(double price)
    {
        return price * 0.8;
    }
}

示例2

我们有一个播放器系统,需要实现添加新的播放方式。开发人员在初始设计中,已经定义了 MediaPlayer 类,用于实现将不同的文件类型转换成已知的音视频格式,然后进行播放。在这个情况下,我们可以使用工厂模式来实现扩展。我们可以定义一个 IMediaPlayer 接口,然后实现多个不同的播放策略,使得系统可以随着需求更改而扩展。

interface IMediaPlayer {
    void Play(string fileName);
}

class VLCPlayer : IMediaPlayer {
    public void Play(string fileName)
    {
        Console.WriteLine($"使用 VLC 播放器播放视频 {fileName}");
    }
}

class WindowsPlayer : IMediaPlayer {
    public void Play(string fileName)
    {
        Console.WriteLine($"使用 Windows 播放器播放视频 {fileName}");
    }
}

class MediaPlayer {
    public void Play(string fileName, bool useVlc) {
        if (useVlc) {
            new VLCPlayer().Play(fileName);
        } else {
            new WindowsPlayer().Play(fileName);
        }
    }
}

结语

开放封闭原则是设计模式中非常重要的一条原则,它能够帮助我们更好地设计软件系统,实现代码的可维护性和可扩展性。可以结合各种设计模式灵活使用,来使代码更加优雅和简洁。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈C#设计模式之开放封闭原则 - Python技术站

(0)
上一篇 2023年5月15日
下一篇 2023年5月15日

相关文章

  • docker部署Asp.net core应用的完整步骤

    Docker部署Asp.net Core应用的完整步骤 Docker是一种流行的容器化技术,可以帮助我们轻松地部署和管理应用程序。在本攻略中,我们将介绍如何使用Docker部署Asp.net Core应用程序,并提供两个示例说明。 准备工作 在使用Docker部署Asp.net Core应用程序之前,我们需要完成以下准备工作: 安装Docker。 我们需要在…

    C# 2023年5月16日
    00
  • ASP.NET中Dictionary基本用法实例分析

    下面是ASP.NET中Dictionary基本用法实例分析的攻略: 概述 在ASP.NET中Dictionary是一种非常常用的数据结构,主要用于存储键值对。它可以帮助我们快速查询键对应的值,是一种高效的存储方式。本篇攻略将对ASP.NET中Dictionary的基本用法进行详细的讲解,并且提供两个实例来帮助理解。 Dictionary基本用法 创建Dict…

    C# 2023年6月3日
    00
  • unity通过Mesh网格绘制图形球体

    下面是Unity通过Mesh网格绘制图形球体的完整攻略: 准备工作 首先,在开始绘制球体之前,我们需要先做一些准备工作。 在Unity的场景中创建一个空物体。 给该空物体添加MeshFilter和MeshRenderer组件(如果没有的话),以便我们可以在场景中看到球体。 创建一个新的C#脚本,并将其命名为“MeshCreator”(我们需要用它来实现网格绘…

    C# 2023年6月3日
    00
  • 基于C#制作考试答题系统

    基于C#制作考试答题系统攻略 制作考试答题系统包括设计系统的界面、编写代码实现功能、搭建数据库、测试系统等多个部分。下面将详细讲解制作考试答题系统的完整攻略。 第一步:设计系统界面 考试系统的界面设计要尽可能简洁明了,需要包括考试题目、答案选项、计时器等模块。可以使用C#中的Windows Form应用程序来实现系统的设计。可以参考示例1中的代码: //建立…

    C# 2023年6月1日
    00
  • WinForm中变Enter键为Tab键实现焦点转移的方法

    在WinForm程序中,我们常常需要通过键盘快速切换输入框焦点,Enter键和Tab键都是常见的选项,不过默认情况下,Enter键是用来确定输入的,Tab键是用来作为焦点转移的快捷键。如果我们需要调换这两个按键的功能,我们可以进行如下设置。 方法一:使用Input Key预处理消息 在WinForm中,每个控件都有一个ProcessCmdKey方法,该方法可…

    C# 2023年6月7日
    00
  • C#中的分布式ID生成组件IDGen介绍并给出示例代码

    C#中的IDGen是一个C#实现的Twitter Snowflake算法的ID生成器,可以生成全局唯一的ID,支持高并发场景下的ID生成。在本篇文章中,我们将介绍IDGen的使用方法并提供相关的C#示例代码。 IDGen的介绍 IDGen是一款开源的分布式唯一ID生成器,支持多种ID生成算法,并且可以在高并发场景下快速生成全局唯一的ID。目前支持的ID生成算…

    C# 2023年4月22日
    00
  • C#封装DBHelper类

    下面是我对“C#封装DBHelper类”的完整攻略: 第一步:创建封装类 首先,我们需要创建一个名为DBHelper的类,这个类将会是一个对应于一个数据库连接的封装,提供了一系列的方法来操作数据库。这个类可以采用单例模式,确保整个应用程序只会有一个数据库连接对象。以下是一个简单的DBHelper类的示例: using System; using System…

    C# 2023年5月31日
    00
  • ASP.NET Ref和Out关键字区别分析

    ASP.NET中的Ref和Out关键字都是用来传递参数的,但它们之间的区别是很明显的。 Ref关键字 Ref关键字用于向方法中传递参数。使用该关键字传递参数意味着你正在传递参数的引用(内存地址),而不是参数本身。因此,任何对参数的更改也会对变量本身产生影响。 Ref示例: public void Modify(ref int num) { num += 10…

    C# 2023年5月31日
    00
合作推广
合作推广
分享本页
返回顶部