文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

软件架构设计原则和示例介绍

2024-11-30 14:24

关注

常见的架构设计原则包括以下几个方面:

1. 单一职责原则(Single Responsibility Principle,SRP):一个模块或者类只负责一项功能。

2. 开闭原则(Open-Closed Principle,OCP):软件实体应该对扩展开放,对修改关闭。

3. 里氏替换原则(Liskov Substitution Principle,LSP):所有引用基类对象的代码都能够透明地使用其子类对象。

4. 接口隔离原则(Interface Segregation Principle,ISP):客户端不应该依赖于它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上。

5. 依赖倒置原则(Dependency Inversion Principle,DIP):高层模块不应该依赖于低层模块,二者应该依赖于抽象接口。同时,抽象不应该依赖于细节,细节应该依赖于抽象。

这些原则可以指导我们设计出更加可扩展、可维护、可测试、可复用的架构。

为了更加详细的说明,以下是各个原则的示例代码:

1、单一职责原则(SRP)

// 错误的示例
public class User {
public void requestBook(string bookName) {
// 做一些请求书籍的事情
// ...
// 做一些记录用户行为的事情
logUserAction("request a book");
}
private void logUserAction(string action) {
// 记录用户行为到日志中
// ...
}
}
// 正确的示例
public class User {
public void requestBook(string bookName) {
// 做一些请求书籍的事情
// ...
}
}
public class UserActionLogger {
public void logUserAction(string action) {
// 记录用户行为到日志中
// ...
}
}

在错误的示例中,`User` 类不仅要负责请求书籍的事情,还要负责记录用户行为。这不仅让代码变得复杂,而且不符合单一职责原则。正确的示例分离了不同的职责,把记录用户行为的功能独立成了一个新的类。

2、开闭原则(OCP)

// 错误的示例
public class UserManager {
public void addUser(User user) {
// 添加用户到数据库中
// ...
}
public void deleteUser(User user) {
// 从数据库中删除用户
// ...
}
}
// 新需求:修改用户信息
public class UserManager {
public void addUser(User user) {
// 添加用户到数据库中
// ...
}
public void deleteUser(User user) {
// 从数据库中删除用户
// ...
}
// 新需求:修改用户信息
public void updateUser(User user) {
// 修改用户信息
// ...
}
}
// 正确的示例
public interface IUserManager {
void addUser(User user);
void deleteUser(User user);
}
public class UserManager : IUserManager {
public void addUser(User user) {
// 添加用户到数据库中
// ...
}
public void deleteUser(User user) {
// 从数据库中删除用户
// ...
}
}
public class AdvancedUserManager : IUserManager {
public void addUser(User user) {
// 添加用户到数据库中
// ...
}
public void deleteUser(User user) {
// 从数据库中删除用户
// ...
}
// 新需求:修改用户信息
public void updateUser(User user) {
// 修改用户信息
// ...
}
}

在错误的示例中,当需要添加新的需求(比如修改用户信息)时,我们需要修改 `UserManager` 类。这显然不符合开闭原则。正确的示例使用了接口和不同的实现类分离不同的功能,这样当我们需要添加新的需求时,只需要创建一个新的实现类即可。

3、里氏替换原则(LSP)

// 错误的示例
public class Animal {
public virtual void eat() {
Console.WriteLine("Animal eat");
}
}
public class Dog : Animal {
public override void eat() {
Console.WriteLine("Dog eat");
}
}
public class Cat : Animal {
public override void eat() {
Console.WriteLine("Cat eat");
}
}
public class AnimalFeeder {
public void feed(Animal animal) {
animal.eat();
}
}
static void Main(string[] args) {
AnimalFeeder animalFeeder = new AnimalFeeder();
animalFeeder.feed(new Dog());
animalFeeder.feed(new Cat());
}
// 输出:
// Dog eat
// Cat eat
// 错误的示例,违反了 LSP
public class WildAnimal : Animal {
}
static void Main(string[] args) {
AnimalFeeder animalFeeder = new AnimalFeeder();
animalFeeder.feed(new Dog());
animalFeeder.feed(new WildAnimal()); // 报错!
}

在错误的示例中,我们定义了一个 `WildAnimal` 类继承自 `Animal` 类,但是这个类并没有重写 `eat()` 方法,而是直接继承了父类的实现。当我们尝试用 `WildAnimal` 对象来调用 `AnimalFeeder` 的 `feed()` 方法时,会出现运行时异常,因为 `WildAnimal` 对象没有正确处理 `eat()` 方法。

4、接口隔离原则(ISP)

// 错误的示例
public interface IAnimal {
void eat();
void fly();
}
public class Dog : IAnimal {
public void eat() {
Console.WriteLine("Dog eat");
}
public void fly() {
throw new NotImplementedException(); // 错误的设计,狗不能飞行
}
}
public class Bird : IAnimal {
public void eat() {
Console.WriteLine("Bird eat");
}
public void fly() {
Console.WriteLine("Bird fly");
}
}
public class AnimalFeeder {
public void feed(IAnimal animal) {
animal.eat();
}
}
static void Main(string[] args) {
AnimalFeeder animalFeeder = new AnimalFeeder();
animalFeeder.feed(new Dog()); // 报错!
animalFeeder.feed(new Bird());
}
// 正确的示例
public interface IEatable {
void eat();
}
public interface IFlyable {
void fly();
}
public class Dog : IEatable {
public void eat() {
Console.WriteLine("Dog eat");
}
}
public class Bird : IEatable, IFlyable {
public void eat() {
Console.WriteLine("Bird eat");
}
public void fly() {
Console.WriteLine("Bird fly");
}
}
public class AnimalFeeder {
public void feed(IEatable animal) {
animal.eat();
}
}
static void Main(string[] args) {
AnimalFeeder animalFeeder = new AnimalFeeder();
animalFeeder.feed(new Dog());
animalFeeder.feed(new Bird());
}

在错误的示例中,我们定义了一个 `IAnimal` 接口,其中包含了 `eat()` 和 `fly()` 两个方法。但是不是所有的动物都可以飞行,例如狗就不能飞行。正确的示例把 `IAnimal` 接口拆分成了 `IEatable` 和 `IFlyable` 两个接口,这样我们可以根据实际需要选择使用哪个接口来表示一个动物的能力。

5、依赖倒置原则(DIP)

// 错误的示例
public class UserService {
private readonly UserDAO userDAO;
public UserService() {
this.userDAO = new UserDAO(); // 依赖了具体的实现
}
public void addUser(User user) {
userDAO.addUser(user);
}
}
public class UserDAO {
public void addUser(User user) {
// 添加用户到数据库中
// ...
}
}
// 正确的示例
public interface IUserDAO {
void addUser(User user);
}
public class UserDAO : IUserDAO {
public void addUser(User user) {
// 添加用户到数据库中
// ...
}
}
public class UserService {
private readonly IUserDAO userDAO;
public UserService(IUserDAO userDAO) {
this.userDAO = userDAO; // 依赖抽象接口
}
public void addUser(User user) {
userDAO.addUser(user);
}
}
static void Main(string[] args) {
IUserDAO userDAO = new UserDAO();
UserService userService = new UserService(userDAO);
userService.addUser(new User());
}

在错误的示例中,`UserService` 类需要访问数据库添加用户,但是直接依赖了 `UserDAO` 类。这使得 `UserService` 类不灵活,不能适应变化。正确的示例中,我们把 `UserDAO` 类抽象成了 `IUserDAO` 接口,并且通过构造函数注入了依赖。这样做不仅遵循了依赖倒置原则,而且还能够灵活地替换不同的实现类。

来源:今日头条内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯