面向对象设计原则(C#版一)

 OOPL并非面向对象的全部
通过面向对象编程语言(OOPL)认识到的面向对象,并不是面向对象的全部,甚至只是浅陋的面向对象。
OOPL的三大机制“封装、继承、多态” 可以表达面向对象的所有概念,但这三大机制本身并没有刻画出面向对象的核心精神。换言之,既可以用这三大机制做出“好的面向对象设计”,也可以用这三大机制 做出“差的面向对象设计”。不是使用了面向对象的语言(例如C#),就实现了面向对象的设计与开发!因此我们不能依赖编程语言的面向对象机制,来掌握面向对象。
OOPL没有回答面向对象的根本性问题——我们为什么要使用面向对象?我们应该怎样使用三大机制来实现“好的面向对象”? 我们应该遵循什么样的面向对象原则?
任何一个严肃的面向对象程序员(例如C#程序员),都需要系统地学习面向对象的知识,单纯从编程语言上获得的面向对象知识,不能够胜任面向对象设计与开发。

面向对象设计原则:
SRP单一职责原则
就一个类而言,应该仅有一个引起它变化的原因
OCP开放-封闭原则
软件实体(类,模块,函数等)应该是可扩展的,但是不可修改
LSP替换原则
子类型必须能够替换掉它们的基类
DIP依赖倒置原则
抽象不应该依赖细节.细节应该依赖于抽象
ISP接口隔离原则
不应该强迫客户依赖于它们不用的方法.接口属于客户,不属于他所在的类层次结构
合成/聚合复用原则(CARP)
迪米特法则(LoD)

一、SRP单一职责原则
在SRP(Single Responsibility Principles)中,职责被定义为“变化的原因”(reason for change). 当需求变化时,该变化会反映为类的职责的变化,如果一个类承担了多余一个的职责,那么引起 他变化的的原因就有多个。于是一个职责的变化 可能会抑制这个类的其他职责的能力。最简单的 例子就是如果你改变了一个多职责类的一个职责,你必须测试所有其他使用这个类另外的职责的 程序,如果忘记这样,可能会导致不可预测的失败
两个职责应该被分开吗?也不一定,当应用程序的变化方式总是导致两个职责同时变化,那么就不必分离他们。换句话说,只有变化实际发生时职责才有真正的意义,如果没有征兆,就去应用SRP是不明智的。这也是敏捷开发一贯的作风,对敏捷开发的其他原则也是这样。
持久化,一个常见的违反SRP的情形就是把业务规则和持久化子系统邦定到一起,这无疑是自找苦吃,业务规则往往会频繁的变化,而持久化的的方式却不会经常变化。
SRP 是最简单也是最难正确运用的原则之一,软件设计真正要做的许多内容,就是发现职责,并把他们互相分离。

 单一职责举例:下图中计算几何应用需要计算图形面积,几何应用只是画图,如果把他们放到一个类中,那么计算几何应用部署的时候就要带着GUI,很不合理。

单一职责原则1

如果把他们职责分开,如下图,就很好的解决了上述问题

单一职责原则2.

二、"开放-封闭"原则(OCP)
Open-Closed Principle原则讲的是:一个软件实体应当对扩展开放,对修改关闭。
优点:
通过扩展已有软件系统,可以提供新的行为,以满足对软件的新的需求,使变化中的软件有一定的适应性和灵活性。
已有软件模块,特别是最重要的抽象层模块不能再修改,这使变化中的软件系统有一定的稳定性和延续性。

关键是抽象

ocp

上图上半部分展示了一个简单不遵循OCP的设计。Client类和Server类都是具体类。Client类使用Server类。如果我们希望Client对象使用另外一个不同的服务器对象,那么就必须要把Client类中使用的Server类的地方更改为新的服务器类。
而右图下半部分展示了一个针对上述问题的遵循OCP的设计。在这个设计中,ClientInterface类是一个拥有抽象成员函数的抽象类。Client类使用这个抽象类;然而Client类的对象却使用Server类的派生类的对象。如果我们希望Client对象使用不同的服务器类,那么只需从ClientInterface类派生一个新的类。而无需对Client类做任何改动

以下是一个不遵循ocp原则的例子

  namespace  DisobeyOCP
    
{
        
enum ShapeType
        
{
            Square,
            Circle
        }

        
class Shape
        
{
            
public virtual ShapeType GetShapType()
            
{
                
return ShapeType.Circle;
            }

        }

        
class Square : Shape
        
{
            Point itsTopLeft;
            
double itsSide;
            
public override ShapeType GetShapType()
            
{
                
return ShapeType.Square;
            }


        }

        
class Circle : Shape
        
{
            Point itsCenter;
            
double itsRadius;
            
public override ShapeType GetShapType()
            
{
                
return ShapeType.Circle;
            }

        }

        
class Point
        
{
            
double x;
            
double y;
        }

        
class DisobeyOCP
        
{
            
public void DrawAllShapes(Shape[] list)
            
{
                
for (int i = 0; i < list.Length; i++)
                
{
                    
switch (list[i].GetShapType())
                    
{
                        
case ShapeType.Circle:
                            DrawCircle((Circle)list[i]);
                            
break;
                        
case ShapeType.Square:
                            DrawSquare((Square)list[i]);
                            
break;
                    }

                }

            }

            
private void DrawSquare(Square s)
            
{
                Console.WriteLine(
"square");
            }

            
private void DrawCircle(Circle c)
            
{
                Console.WriteLine(
"circle");
            }


        }

    }

上例中加入一个新图形时,需要大量改动DrawAllShapes代码

调用方法为

            DisobeyOCP.Shape[] list = new DisobeyOCP.Shape[2];
            DisobeyOCP.Circle c = new DisobeyOCP.Circle();
            list[0] = c;
            DisobeyOCP.Square s = new DisobeyOCP.Square();
            list[1] = s;
            DisobeyOCP.DisobeyOCP dis = new DisobeyOCP.DisobeyOCP();
            dis.DrawAllShapes(list);

以下为改善后的代码,遵循了ocp原则

namespace  ObeyOCP
    
{
        
        
abstract class Shape
        
{
            
            
public abstract void draw();
        }

        
class Square : Shape
        
{
            Point itsTopLeft;
            
double itsSide;
            
public override void draw()
            
{
                Console.WriteLine(
"square");
            }

        }

        
class Circle : Shape
        
{
            Point itsCenter;
            
double itsRadius;
 
            
public override void draw()
            
{
                Console.WriteLine(
"circle");
            }

        }

        
class Point
        
{
            
double x;
            
double y;
        }

        
class ObeyOCP
        
{
            
public void DrawAllShapes(Shape[] list)
            
{
                
for (int i = 0; i < list.Length; i++)
                
{
                    list[i].draw();
                }

            }

           

        }

    }

加入新图形时不用修改已存在代码

调用方法为:

            ObeyOCP.Shape[] list = new ObeyOCP.Shape[2];
            ObeyOCP.Circle c = new ObeyOCP.Circle();
            list[0] = c;
            ObeyOCP.Square s = new ObeyOCP.Square();
            list[1] = s;
            ObeyOCP.ObeyOCP dis = new ObeyOCP.ObeyOCP();
            dis.DrawAllShapes(list);

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值