概括阐论软件开发过程中的方法,并用 python,Java和C++ 语言举实例说明之

现在将软件开发中的核心方法论分为几类,并结合 Python、Java 和 C++ 的实例进行说明。这些方法论是解决复杂问题的通用思维模式。

一、 核心方法论概述

  1. 抽象与具体

    • 抽象:隐藏复杂的实现细节,只暴露必要的接口或属性。这是管理复杂性的基石。
    • 具体:抽象概念的具体实现。关注“如何做”的细节。
    • 关系:通过抽象定义契约,通过具体实现功能。
  2. 一般与特殊(继承与多态)

    • 一般:定义通用的类、接口或模板。代表共性。
    • 特殊:从一般化定义中派生出特定化的版本,可以继承、覆盖或特化。代表特性。
    • 关系:实现代码复用和行为扩展。
  3. 分而治之

    • 将一个大问题分解为若干个相同或相似的小问题,递归求解,再合并结果。常见于算法设计(如排序、搜索)。
  4. 组合优于继承

    • 通过将对象作为其他对象的字段(组合)或通过接口协作来构建复杂功能,而非单纯依靠类继承树。这提高了灵活性和可维护性。
  5. 关注点分离

    • 将系统分解为不同的部分,每一部分只负责一个特定的功能领域(如数据访问、业务逻辑、用户界面)。MVC、分层架构就是其体现。
  6. 契约式设计

    • 明确规定函数或方法的前置条件后置条件不变式。确保组件在满足约定时正确工作。

二、 实例说明

我们将用三个例子来贯穿上述方法,并用三种语言实现。

例子场景:图形计算系统
  1. 定义一个抽象的 Shape
  2. 实现具体的 CircleRectangle
  3. 使用组合设计一个复杂的 Drawing(画布)。
  4. 演示分而治之(计算面积之和)。
  5. 演示契约设计(输入验证)。

1. 抽象与具体 & 一般与特殊

Python

from abc import ABC, abstractmethod
import math

# 抽象 & 一般
class Shape(ABC):
    @abstractmethod
    def area(self):
        pass  # 抽象方法,无具体实现

    def describe(self): # 具体方法,可被继承
        return f"I am a shape."

# 具体 & 特殊
class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self): # 实现抽象方法
        return math.pi * self.radius ** 2

    def describe(self): # 覆盖父类方法
        return f"I am a Circle with radius {self.radius}."

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

# 使用
shapes = [Circle(5), Rectangle(3, 4)]
for s in shapes:
    print(s.describe(), f"Area: {s.area()}")
# 输出体现了多态:同一个接口,不同行为

Java

// 抽象 & 一般
abstract class Shape {
    public abstract double area(); // 抽象方法
    public String describe() { // 具体方法
        return "I am a shape.";
    }
}

// 具体 & 特殊
class Circle extends Shape {
    private double radius;
    public Circle(double radius) { this.radius = radius; }
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
    @Override
    public String describe() {
        return "I am a Circle with radius " + radius;
    }
}

class Rectangle extends Shape {
    private double width, height;
    public Rectangle(double w, double h) { width = w; height = h; }
    @Override
    public double area() { return width * height; }
}

public class Main {
    public static void main(String[] args) {
        Shape[] shapes = {new Circle(5), new Rectangle(3, 4)};
        for (Shape s : shapes) {
            System.out.println(s.describe() + " Area: " + s.area());
        }
    }
}

C++

#include <iostream>
#include <vector>
#include <string>
#include <cmath>
using namespace std;

// 抽象 & 一般
class Shape {
public:
    virtual double area() const = 0; // 纯虚函数,使类成为抽象类
    virtual string describe() const { return "I am a shape."; }
    virtual ~Shape() {} // 虚析构函数,确保正确释放资源
};

// 具体 & 特殊
class Circle : public Shape {
    double radius;
public:
    Circle(double r) : radius(r) {}
    double area() const override {
        return M_PI * radius * radius;
    }
    string describe() const override {
        return "I am a Circle with radius " + to_string(radius);
    }
};

class Rectangle : public Shape {
    double width, height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    double area() const override { return width * height; }
};

int main() {
    vector<Shape*> shapes = {new Circle(5), new Rectangle(3, 4)};
    for (auto s : shapes) {
        cout << s->describe() << " Area: " << s->area() << endl;
        delete s; // 清理内存
    }
    return 0;
}

2. 组合优于继承 & 关注点分离

我们创建一个 Drawing 类,它组合了多个 Shape 对象。Drawing 只负责管理形状集合,不关心单个形状的具体计算(关注点分离)。

Python

class Drawing:
    def __init__(self):
        self.shapes = [] # 组合:持有其他对象的引用

    def add_shape(self, shape: Shape): # 依赖于抽象Shape,而非具体类
        self.shapes.append(shape)

    def total_area(self):
        # 分而治之:将“求总面积”分解为“求每个形状面积并求和”
        total = 0
        for shape in self.shapes:
            total += shape.area() # 委托给各个具体对象
        return total

    def describe_all(self):
        return [s.describe() for s in self.shapes]

# 使用
drawing = Drawing()
drawing.add_shape(Circle(5))
drawing.add_shape(Rectangle(3, 4))
print(f"Total Area: {drawing.total_area()}")
print(f"Descriptions: {drawing.describe_all()}")

Java

import java.util.ArrayList;
import java.util.List;

class Drawing {
    private List<Shape> shapes = new ArrayList<>(); // 组合

    public void addShape(Shape shape) {
        shapes.add(shape);
    }

    public double totalArea() {
        double total = 0;
        for (Shape s : shapes) {
            total += s.area(); // 委托
        }
        return total;
    }

    public List<String> describeAll() {
        List<String> desc = new ArrayList<>();
        for (Shape s : shapes) {
            desc.add(s.describe());
        }
        return desc;
    }
}

public class Main {
    public static void main(String[] args) {
        Drawing drawing = new Drawing();
        drawing.addShape(new Circle(5));
        drawing.addShape(new Rectangle(3, 4));
        System.out.println("Total Area: " + drawing.totalArea());
        System.out.println("Descriptions: " + drawing.describeAll());
    }
}

C++

class Drawing {
    vector<Shape*> shapes; // 组合:使用指针集合
public:
    void addShape(Shape* s) {
        shapes.push_back(s);
    }

    double totalArea() const {
        double total = 0;
        for (const auto& s : shapes) {
            total += s->area(); // 委托
        }
        return total;
    }

    vector<string> describeAll() const {
        vector<string> desc;
        for (const auto& s : shapes) {
            desc.push_back(s->describe());
        }
        return desc;
    }

    ~Drawing() {
        for (auto s : shapes) {
            delete s; // 清理资源
        }
    }
};

int main() {
    Drawing drawing;
    drawing.addShape(new Circle(5));
    drawing.addShape(new Rectangle(3, 4));
    cout << "Total Area: " << drawing.totalArea() << endl;
    auto desc = drawing.describeAll();
    for (const auto& d : desc) {
        cout << d << endl;
    }
    // drawing析构时会自动delete所有shape
    return 0;
}

3. 契约式设计

我们通过前置条件验证来演示契约思想。

Python (使用类型提示和 assertif 检查)

class ValidatedRectangle(Rectangle):
    def __init__(self, width, height):
        # 前置条件契约:宽度和高度必须为正数
        if not (isinstance(width, (int, float)) and width > 0):
            raise ValueError("Width must be a positive number.")
        if not (isinstance(height, (int, float)) and height > 0):
            raise ValueError("Height must be a positive number.")
        # 不变式契约:创建后,width和height应保持不变(除非提供修改方法并同样验证)
        super().__init__(width, height)

    # 后置条件契约示例:area() 的返回值应 >= 0
    # 在这个简单例子中,由于构造时已验证,后置条件自然满足。

Java (使用 IllegalArgumentException)

class ValidatedRectangle extends Rectangle {
    public ValidatedRectangle(double width, double height) {
        super(width, height); // 先调用父类构造
        // 前置条件验证(更严格的做法应在赋值前验证)
        if (width <= 0 || height <= 0) {
            throw new IllegalArgumentException("Width and height must be positive.");
        }
        // 不变式:this.width > 0 && this.height > 0
    }
}

C++ (使用 exceptionsassert)

class ValidatedRectangle : public Rectangle {
public:
    ValidatedRectangle(double width, double height) : Rectangle(width, height) {
        // 前置条件验证
        if (width <= 0 || height <= 0) {
            throw std::invalid_argument("Width and height must be positive.");
        }
        // 或者使用 assert (仅在调试模式生效)
        // assert(width > 0 && height > 0);
    }
    // 后置条件:area() > 0 在构造函数验证后成立
};

4. 其他重要方法补充

  • 迭代与递归:解决问题的一种重复机制。

    • 实例:计算斐波那契数列。
    # Python 迭代
    def fib_iterative(n):
        a, b = 0, 1
        for _ in range(n):
            a, b = b, a + b
        return a
    
    # Python 递归 (分而治之的体现)
    def fib_recursive(n):
        if n <= 1:
            return n # 基本情况
        return fib_recursive(n-1) + fib_recursive(n-2) # 分解问题
    
  • 配置与约定:通过外部配置(如文件、环境变量)改变行为,或遵循特定约定(如Java Bean的getter/setter)。

  • 依赖注入:将对象的依赖从内部创建改为外部传入,实现控制反转,提高可测试性。Spring框架是典范。

总结

方法核心思想示例体现
抽象与具体隐藏细节,暴露接口Shape 抽象类与 Circle 具体类
一般与特殊继承共性,扩展特性Shape 作为父类,Rectangle 继承并实现 area()
分而治之分解、解决、合并Drawing.total_area() 循环求和
组合优于继承通过包含而非继承构建功能Drawing 类包含 Shape 列表
关注点分离模块各司其职Shape 管计算,Drawing 管集合,Main 管流程
契约式设计明确前提、保证结果ValidatedRectangle 的构造参数验证

这些方法不是孤立的,而是交织在优秀的软件设计中。例如,Drawing 类使用组合(持有Shape列表),遵循关注点分离(只管理集合),其 total_area 方法体现了分而治之,并且它依赖于抽象Shape 类,通过多态(一般与特殊)调用具体实现,在添加形状时可能还会用到契约验证。掌握这些思维模式,能让你在使用任何语言进行开发时,都能写出结构清晰、易于维护的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千江明月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值