0x05、设计模式原则 —— 开闭原则
开闭原则(Open Closed Principle) 是编程中最基础、最重要的设计原则
一个软件实体,比如:类,模块和函数应该对扩展开放(对提供方而言), 对修改关闭(对使用方而言)。 用抽象构建框架,用实现扩展细节。
当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。
演示
假设有如下UML类图,Retangle矩形类 和 Circle圆形类 继承至 Shape;
上图代码实现:
public static void Main(string[] args) { GraphicEditor graphicEditor = new GraphicEditor(); graphicEditor.drawShape(new Rectangle()); graphicEditor.drawShape(new Circle()); } /// <summary> /// 绘制操作【使用方】 /// </summary> class GraphicEditor { public void drawShape(Shape s) { if (s.m_type == 1) drawRectangle(s); else if (s.m_type == 2) drawCircle(s); } public void drawRectangle(Shape r) { Console.WriteLine(" 绘制矩形 "); } public void drawCircle(Shape r) { Console.WriteLine(" 绘制圆形 "); } } /// <summary> /// 图形 基类 /// </summary> public class Shape { public int m_type; } /// <summary> /// 矩形类 /// </summary> public class Rectangle : Shape { public Rectangle() { m_type = 1; } } /// <summary> /// 圆形类 /// </summary> public class Circle : Shape { public Circle() { m_type = 2; } }
上面代码中,违反了设计模式的ocp原则(对扩展开放(提供方),对修改关闭(使用方))。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码;
比如我们这时要新增加一个图形种类 三角形,我们需要做如下修改, 修改的地方较多:
public static void Main(string[] args) { GraphicEditor graphicEditor = new GraphicEditor(); graphicEditor.drawShape(new Rectangle()); graphicEditor.drawShape(new Circle()); graphicEditor.drawShape(new Trianle()); // 新增!! } /// <summary> /// 绘制操作【使用方】 /// </summary> class GraphicEditor { public void drawShape(Shape s) { if (s.m_type == 1) drawRectangle(s); else if (s.m_type == 2) drawCircle(s); else if (s.m_type == 3) // 使用方这里新增一个判断!!!(即修改了使用方) drawTrianle(s); } public void drawRectangle(Shape r) { Console.WriteLine(" 绘制矩形 "); } public void drawCircle(Shape r) { Console.WriteLine(" 绘制圆形 "); } public void drawTrianle(Shape r) // 使用方这里新增一个方法!!!(即修改了使用方) { Console.WriteLine(" 绘制三角形 "); } } /// <summary> /// 图形 基类 /// </summary> public class Shape { public int m_type; } /// <summary> /// 矩形类 /// </summary> public class Rectangle : Shape { public Rectangle() { m_type = 1; } } /// <summary> /// 圆形类 /// </summary> public class Circle : Shape { public Circle() { m_type = 2; } } /// <summary> /// 三角形类 /// </summary> public class Trianle : Shape // 新增!!! { public Trianle() { m_type = 3; } }
上面只是扩充了一个三角形,就需要改动【使用方】的代码,这违背了 开闭原则,我们怎么改进它呢?
改进方式思路: 把Shape类做成抽象类,并提供一个抽象的draw方法,让子类去实现即可,这样我们有新的图形种类时,只需要让新的图形类继承Shape,并实现draw方法即可,使用方的代码就不需要修 -> 这样就满足了开闭原则~
即:
public static void Main(string[] args) { GraphicEditor graphicEditor = new GraphicEditor(); graphicEditor.drawShape(new Rectangle()); graphicEditor.drawShape(new Circle()); graphicEditor.drawShape(new Trianle()); } /// <summary> /// 绘制操作【使用方】 /// </summary> class GraphicEditor { public void drawShape(Shape s) { s.draw(); } } /// <summary> /// 图形 基类 /// </summary> public abstract class Shape { public int m_type; public abstract void draw(); } /// <summary> /// 矩形类 /// </summary> public class Rectangle : Shape { public Rectangle() { m_type = 1; } public override void draw() { Console.WriteLine(" 绘制矩形 "); } } /// <summary> /// 圆形类 /// </summary> public class Circle : Shape { public Circle() { m_type = 2; } public override void draw() { Console.WriteLine(" 绘制圆形 "); } } /// <summary> /// 三角形类 /// </summary> public class Trianle : Shape { public Trianle() { m_type = 3; } public override void draw() { Console.WriteLine(" 绘制三角形 "); } }
修改成这样后,如果我们需要增加一个其他图形的话,那么 只是新增一个 OtherGraphic 类并在 Main 函数中调用即可:
public static void Main(string[] args) { GraphicEditor graphicEditor = new GraphicEditor(); graphicEditor.drawShape(new Rectangle()); graphicEditor.drawShape(new Circle()); graphicEditor.drawShape(new Trianle()); graphicEditor.drawShape(new OtherGraphic()); // -- 新增 } /// <summary> /// 绘制操作【使用方】 /// </summary> class GraphicEditor { public void drawShape(Shape s) { s.draw(); // 不需要改动 } } /// <summary> /// 图形 基类 /// </summary> public abstract class Shape { public int m_type; public abstract void draw(); } /// <summary> /// 矩形类 /// </summary> public class Rectangle : Shape { public Rectangle() { m_type = 1; } public override void draw() { Console.WriteLine(" 绘制矩形 "); } } /// <summary> /// 圆形类 /// </summary> public class Circle : Shape { public Circle() { m_type = 2; } public override void draw() { Console.WriteLine(" 绘制圆形 "); } } /// <summary> /// 三角形 类 /// </summary> public class Trianle : Shape { public Trianle() { m_type = 3; } public override void draw() { Console.WriteLine(" 绘制三角形 "); } } /// <summary> /// 其他形 类 /// </summary> public class OtherGraphic : Shape // -- 新增 { public OtherGraphic() { m_type = 4; } public override void draw() { Console.WriteLine(" 绘制其他形 "); } }
这样,我们的代码就完美的实现了开闭原则了;
有木有发现,这个写法和之前的讲到的 依赖倒置原则 很像?
注意了,这个开闭原则很重要的,面试要考的~~而且,也不难啊~~加油,最后两个原则,下一章:迪米特法则