设计模式

如何解决复杂的问题?
  • 分解
  • 抽象
    下面两段代码是写一个画图工具分别采用分解和抽象的处理方法.
    可以看出抽象的处理方法更易于扩展(增加类, 而非在之前的函数中进行添加或修改),改变的地方更少. 随着设计模式的深入学习, 我们可以将抽象中函数的改变也去掉
class Point {
    public:
        int x;
        int y;

};
class Line {
public:
    Point start;
    Point end;

    Line(const Point& start, const Point& end)
    {
        this->start = start;
        this->end = end;
    }
};
  
//矩形
class Rect {
public:
    Point leftUp;
    int width;
    int height;

    Rect(const Point& leftUp, int width, int height)
    {
        this->leftUp = leftUp;
        this->width = width;
        this->height = height;
    }
};
//增加
class Circle{
public:
	Point p;
	int r;
	Circle(const Point & p, int r)
	{
		//...
	}
};
class From;
class MainFrom : public Form {
private:
    Point p1, p2;
    vector<Line> lineVector;
    vector<Rect> rectVector;
    vector<Circle> rectVector; //改变
    
    MainFrom()
    {
        //...
    }
protected:
    virtual void onMouseDown(const MouseEventArgs& e);
    virtual void onMouseUp(const MouseEventArgs& e);
    virtual void onPoint(const MouseEventArgs& e);
};

void MainFrom::onMouseDown(const MouseEventArgs& e)
{
    p1.x = e.x;
    p1.y = e.y;

    From::onMouseDown(e);
}

void MainFrom::onMouseUp(const MouseEventArgs& e)
{
    p2.x = e.x;
    p2.y = e.y;

    if (rdoLine.checked) {
        Line line(p1, p2);
        lineVector.push_back(line);
    }
    else if (rdoRect.checked) {
        int width = abs(p2.x - p1.x);
        int height = abs(p2.y - p1.y);
        Rect rect(p1, width, height);
        rectVector.push_back(rect);
    }
    else if () { //改变
        //...
        CircleVector.push_back(circle);
    }

    //...
    this->refresh();
    From::onMouseUp(e);
}

void MainFrom::onPoint(const PointEventArgs& e)
{
    for (int i = 0; i < lineVectror.size(); i++) {
        e.Graphics.DrawLine(Pens.red, lineVector[i].start.x, lineVector[i].start.y,
                                      lineVector[i].end.x, lineVector[i].end.y);
    }
    for (int i = 0; i < rectVectror.size(); i++) {
        e.Graphics.DrawRectangle(Pens.red, RectVector[i].leftUp, 
                                           RectVector[i].width, 
                                           RectVector[i].height);
    }
    //改变
    for (int i = 0; i < circleVectror.size(); i++) {
        e.Graphics.DrawCircle(Pens.red, circleVector[i]);
    }

    From::onPoint(e);
}
class Shape {
public:
	virtual void Draw(const Graphics& g) = 0;
	virtual ~Shape() { }
};

class Point {
public:
    int x;
    int y;
};

class Line : public Shape {
public:
	Point start;
	Point end;
	
	Line(const Point& start, const Point& end) 
    {
		this->start = start;
		this->end = end;
	}

	virtual void Draw(const Graphics& g) 
    {
		g.DrawLine(Pens.Red, start.x, start.y, end.x, end.y);
	}
};

class Rect : public Shape {
public:
    Point leftUp;
    int width;
    int height;

    Rect(const Point& leftUp, int width, int height) 
    {
       this->leftUp = leftUp;
	   this->width = width;
       this->height = height;
    }
    virtual void Draw (const Graphics& g) 
    { 
        g.DrawReactangle(Pens.red, leftUp, width, height); 
    }
};

//增加
class Circle : public Shape{
public:
	//实现自己的Draw,负责画自己
	virtual void Draw(const Graphics& g){
		g.DrawCircle(Pens.Red,
			...);
	}
};

class MainFrom : public From {
private:
	Point p1;
	Point p2;
	vector<Shape*> shapeVector;

public:
    MainFrom() {  }

protected:
    virtual void onMouseDown(const MouseEventArgs& e);
    virtual void onMouseUp(const MouseEventArgs& e);
    virtual void onPaint(const MouseEventArgs& e);

};

void MainFrom:: OnMouseUP(const MouseEventArgs& e)
{
    p2.x = e.x;
    p2.y = e.y;
    //...
	Form::OnMouseDown(e);
}

void MainForm::OnMouseUp(const MouseEventArgs& e){
	p2.x = e.X;
	p2.y = e.Y;

	if (rdoLine.Checked){
		shapeVector.push_back(new Line(p1,p2));
	}
	else if (rdoRect.Checked){
		int width = abs(p2.x - p1.x);
		int height = abs(p2.y - p1.y);
		shapeVector.push_back(new Rect(p1, width, height));
	}
	//改变
	else if (...){
		//...
		shapeVector.push_back(circle);
	}
	//...
	this->Refresh();
	Form::OnMouseUp(e);
}

void MainForm::OnPaint(const PaintEventArgs& e){

	//针对所有形状
	for (int i = 0; i < shapeVector.size(); i++){
		shapeVector[i]->Draw(e.Graphics); //多态调用,各负其责
	}
	//...
	Form::OnPaint(e);
}

在这里插入图片描述

什么是好的软件设计? 软件设计的金科玉律:

复用

重新认识面向对象

我们之前认识的面向对象就是封装 继承 多态, 但这是底层逻辑, 我们应该建立更高级别的抽象

理解隔离变化
- 从宏观层面来看, 面向对象的构建方式更能适应软件的变化, 能将变化所带来的影响减为最小
各司其职
- 从微观层面来看, 面向对象的方式更强调各个类的"责任"
- 由于需求变化导致的新增类型不应该影响原来类型的实现–是所谓各负其责
对象是什么?
- 从语言实现层面来讲, 对象封装了代码和数据
- 从规格层面来讲, 对象是一系列可被使用的公共接口
- 从概念层面来讲, 对象是拥有某种责任的抽象

面向对象设计原则

  • 依赖倒置原则

    • 高层模型(稳定)不应该依赖于底层模块(变化), 二者都应该依赖于抽象(稳定)
    • 抽象(稳定)不应该依赖于实现细节(变化), 实现细节应该依赖于抽象(稳定)
  • 开放封闭原则

    • 对扩展开放, 对更改封闭
    • 类模块应该是可扩展的, 但是不可修改的
  • 单一职责原则(SPR)

    • 一个类应该仅有一个引起它变化的原因
    • 变化的方向隐含着类的责任
  • LisKov替换原则(LSP)

    • 子类必须能够替换他们的基类(IS-A)
    • 继承表达类型抽象
  • 接口隔离原则(ISP)

    • 不应该强迫客户程序依赖他们不用的方法
    • 接口应该小而完备
  • 优先使用对象组合, 而不是类继承

    • 类继承通常为"白箱复用", 对象继承通常为"黑箱复用"
    • 继承在某种程度上破坏了封装性, 子类父类耦合度高
    • 而对象组合则只要求被组合的对象具有良好定义的接口, 耦合度低
  • 封装变化点

    • 使用封装来创建对象之间的分界层, 让设计者可以在分界层一侧进行修改, 而不会对一侧产生不良影响, 从而实现松耦合
  • 针对接口编程, 而不是针对实现编程

    • 不将变量类型声明为某个特定的具体类, 而是声明为某个接口
    • 客户程序无需获知对象的具体类型, 只需要知道对象所具有的接口
    • 减少系统中各部分的依赖关系, 从而实现"高内聚, 松耦合"的类型设计方案

产业强盛的标志—接口标准化

GOF-23模式分类
从目的来看:

  • 创建型(Creational)模式: 将对象的部分创建工作延迟到子类或者其他对象, 从而应对需求变化为对象创建时具体类型实现引来的冲击.
  • 结构型(Structural)模式 : 通过类继承或者对象组合获得更灵活的结构, 从而应对需求变化为对象的结构带来的冲击
  • 行为型(Behavioral)模式: 通过类继承或者对象组合来划分类与对象间的职责, 从而应对需求变化为多个交互的对象带来冲击.

从范围来看:

  • 类模式: 处理类与子类的静态关系, 继承
  • 对象模式: 处理对象间的动态关系, 组合
    在这里插入图片描述

好的面向对象设计: 应对变化, 提高复用
现代软件设计的特征是需求的频繁变化, 设计模式就是要寻找变化点, 然后在变化点出应用设计模式
敏捷软件开发提倡的是"Refactoring to Patterns"

重构关键技法:
1. 静态 -> 动态
2. 早绑定 -> 晚绑定
3. 继承 -> 组合
4. 编译时依赖 -> 运行时依赖
5. 紧耦合 -> 松耦合

下面的博客陆续更新各个设计模式, 敬请期待…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值