理解OCP原则

   面向对象可利用设计(OOD)的第一块基石,就是"-闭原则(Open-Closed Principle,简称OCP)。OCP原则认为:一个软件应该对扩展开放,对修改关闭。 这是由大师Bertrand Meyer提出,英文原文是: Software entities should be open for extension,but closed for modification. 那么怎么在程序设计中做到遵循OCP原则,进行面向对象程序设计呢?在这个问题上很多大师都说是 经验+技巧 才可以达到用OCP原则来指导面向对象程序设计。本人学了一段时间,可是还没有完全领悟OCP原则,下面以求解一元二次方程的根为例,通过5次改进达到使用OCP原则指导面向对象程序设计。下面的代码都是在WinXp Sp2 + C# 下调试通过的。

第一次------完全面向过程的写法可以说就是一个C程序用C#重新包装了一下

using System;
namespace
 equation1
{
  
/// <summary>

  
/// Class1 的摘要说明。
  
/// </summary>

  class Class1
  {
    
/// <summary>

    
/// 应用程序的主入口点。
    
/// </summary>

    [STAThread]
    
static void Main(string
[] args)
    {
      
string
 A;
      
string
 B;
      
string
 C;
      
int
 a;
      
int
 b;
      
int
 c;
      
bool
 bPlural;
      
string
 X1;
      
string
 X2;
      System.Console.Write(
"Please input the modulus A = "
);
      A
=
System.Console.ReadLine();
      System.Console.Write(
"Please input the modulus B = "
);
      B
=
System.Console.ReadLine();
      System.Console.Write(
"Please input the modulus C = "
);
      C
=
System.Console.ReadLine();
      
try

      {
        a
=int.Parse(A);
        b
=int
.Parse(B);
        c
=int
.Parse(C);
      }
      
catch

      {
        System.Console.WriteLine(
"Input error!!!");
        
return
;
      }

double dt;
      dt
=b*b-4*a*
c;
      bPlural
=dt>=0?false:true
;
      dt
=
System.Math.Abs(dt);
      dt
=
System.Math.Sqrt(dt);
      
double
 x1;
      
double
 x2;
      
if
(bPlural)
      
{
        x1
=dt/2/
a;
        x2
=(0-b)/2/
a;
        X1
=x2.ToString()+"+"+x1.ToString()+"i"
;
        x1
=0-
x1;
        X2
=x2.ToString()+x1.ToString()+"i"
;
      }

      
else
      
{
        x1
=(dt-b)/2/
a;
        x2
=(0-b-dt)/2/
a;
        X1
=
x1.ToString();
        X2
=
x2.ToString();
      }

      System.Console.WriteLine(
"X1 = {0}",X1);
      System.Console.WriteLine(
"X2 = {0}"
,X2);
    }
  }
}
第二次------抽象了一个方程类 不过数据和操作完全耦合在一起
using System;
namespace equation2
{
  
/**********************************/
  
//eqtion抽象出的方程类 //
  
//int a int b int c 分别为方程的系数 //
  
//string X1 string X2 为方程的两个根 //
  
//public void operation() 为方程求解的操作//
  /*********************************/
  
public class eqtion
  
{
    
public eqtion(int a,int b,int c)
    
{
      
this.a=a;
      
this.b=b;
      
this.c=c;
      
//
      
// TODO: 在此处添加构造函数逻辑
      
//
    }

    
public void operation()
    
{
      
double dt;
      dt
=b*b-4*a*c;
      
bool bPlural=dt>=0?false:true;
      dt
=System.Math.Abs(dt);
      dt
=System.Math.Sqrt(dt);
      
double x1;
      
double x2;
      
if(bPlural)
      
{
        x1
=dt/2/a;
        x2
=(0-b)/2/a;
        X1
=x2.ToString()+"+"+x1.ToString()+"i";
        x1
=0-x1;
        X2
=x2.ToString()+x1.ToString()+"i";
      }

      
else
      
{
        x1
=(dt-b)/2/a;
        x2
=(0-b-dt)/2/a;
        X1
=x1.ToString();
        X2
=x2.ToString();
      }

    }

    
~eqtion(){}
    
private int a;
    
private int b;
    
private int c;
    
public string X1;

  public string X2;
  }
}
using System;
namespace equation2
{
  
/// <summary>
  
/// Class1 的摘要说明。
  
/// </summary>

  class Class1
  
{
    
/// <summary>
    
/// 应用程序的主入口点。
    
/// </summary>

    [STAThread]
    
static void Main(string[] args)
    
{
      
string A;
      
string B;
      
string C;
      
int a;
      
int b;
      
int c;
      System.Console.Write(
"Please input the modulus A = ");
      A
=System.Console.ReadLine();
      System.Console.Write(
"Please input the modulus B = ");
      B
=System.Console.ReadLine();
      System.Console.Write(
"Please input the modulus C = ");
      C
=System.Console.ReadLine();
      
try
      
{
        a
=int.Parse(A);
        b
=int.Parse(B);
        c
=int.Parse(C);
      }

      
catch
      
{
        System.Console.WriteLine(
"Input error!!!");
        
return;
      }

      eqtion Opeqtion 
=new eqtion(a,b,c);
      Opeqtion.operation();
      System.Console.WriteLine(
"X1 = {0}",Opeqtion.X1);
      System.Console.WriteLine(
"X2 = {0}",Opeqtion.X2);
    }

  }

}

第三次------抽象的方程类中数据和操作完全聚合在一起

using System;
namespace equation3
{
  
/*******************************************/
  
//eqtion抽象出的方程类 //
  
//string X1 string X2 为方程的两个根 //
  
//public eqtion() 既是类的构造函数又是方程求解的操作//
  /*******************************************/
  
public class eqtion
  
{
    
public eqtion(int a,int b,int c)
    
{
      
double dt;
      dt
=b*b-4*a*c;
      
bool bPlural=dt>=0?false:true;
      dt
=System.Math.Abs(dt);
      dt
=System.Math.Sqrt(dt);
      
double x1;
      
double x2;
      
if(bPlural)
      
{
        x1
=dt/2/a;
        x2
=(0-b)/2/a;
        X1
=x2.ToString()+"+"+x1.ToString()+"i";
        x1
=0-x1;
        X2
=x2.ToString()+x1.ToString()+"i";
      }

      
else
      
{
        x1
=(dt-b)/2/a;
        x2
=(0-b-dt)/2/a;
        X1
=x1.ToString();
        X2
=x2.ToString();
      }

    }

    
~eqtion()
    
{
    }

    
public string X1;
    
public string X2;
  }

}

 

using System;
namespace equation3
{
  
/// <summary>
  
/// Class1 的摘要说明。
  
/// </summary>

  class Class1
  
{

    
/// <summary>
    
/// 应用程序的主入口点。
    
/// </summary>

    [STAThread]
    
static void Main(string[] args)
    
{
      
string A;
      
string B;
      
string C;
      
int a;
      
int b;
      
int c;
      System.Console.Write(
"Please input the modulus A = ");
      A
=System.Console.ReadLine();
      System.Console.Write(
"Please input the modulus B = ");
      B
=System.Console.ReadLine();
      System.Console.Write(
"Please input the modulus C = ");
      C
=System.Console.ReadLine();
      
try
      
{
        a
=int.Parse(A);
        b
=int.Parse(B);
        c
=int.Parse(C);
      }

      
catch
      
{
        System.Console.WriteLine(
"Input error!!!");
        
return;
      }

      eqtion Opeqtion 
=new eqtion(a,b,c);
      System.Console.WriteLine(
"X1 = {0}",Opeqtion.X1);
      System.Console.WriteLine(
"X2 = {0}",Opeqtion.X2);
    }

  }

}

第四次------抽象的方程类中只有操作了 数据通过参数传入传出
using System;
namespace equation4
{
  
/********************************************************/
  
//eqtion抽象出的方程类//
  
//string X1 string X为求得的方程的两个根用out方式输出
  
//public eqtion() 既是类的构造函数又是方程求解的操作
  /************************************************************/
  
public class eqtion
  
{
    
public eqtion(int a,int b,int c,out string X1,out string X2)
    
{
      
double dt;
      dt
=b*b-4*a*c;
      
bool bPlural=dt>=0?false:true;
      dt
=System.Math.Abs(dt);
      dt
=System.Math.Sqrt(dt);
      
double x1;
      
double x2;
      
if(bPlural)
      
{
        x1
=dt/2/a;
        x2
=(0-b)/2/a;
        X1
=x2.ToString()+"+"+x1.ToString()+"i";
        x1
=0-x1;
        X2
=x2.ToString()+x1.ToString()+"i";
      }

      
else
      
{
        x1
=(dt-b)/2/a;
        x2
=(0-b-dt)/2/a;
        X1
=x1.ToString();
        X2
=x2.ToString();
      }

    }

    
~eqtion()
    
{
    }

  }

}

using System;
namespace equation4
{
  
/// <summary>
  
/// Class1 的摘要说明。
  
/// </summary>

  class Class1
  
{
    
/// <summary>
    
/// 应用程序的主入口点。
    
/// </summary>

    [STAThread]
    
static void Main(string[] args)
    
{
      
string A;
      
string B;
      
string C;
      
int a;
      
int b;
      
int c;
      System.Console.Write(
"Please input the modulus A = ");
      A
=System.Console.ReadLine();
      System.Console.Write(
"Please input the modulus B = ");
      B
=System.Console.ReadLine();
      System.Console.Write(
"Please input the modulus C = ");
      C
=System.Console.ReadLine();
      
try
      
{
        a
=int.Parse(A);
        b
=int.Parse(B);
        c
=int.Parse(C);
      }

      
catch
      
{
        System.Console.WriteLine(
"Input error!!!");
        
return;
      }

      
string X1,X2;
      eqtion Opeqtion 
=new eqtion(a,b,c,out X1,out X2);
      System.Console.WriteLine(
"X1 = {0}",X1);
      System.Console.WriteLine(
"X2 = {0}",X2);
    }

  }

}

第五次------抽象出两个类 一个专门存数据 一个是操作类 数据和操作完全分离

using System;
namespace equation5
{
  
/************************************************/
  
//eqtion抽象出的方程数据类 //
  
//int a int b int c 分别为方程的系数 //
  
//public int A public intB public int C 为方程的系数和操作类的接口 //
  /************************************************/
  
public class edata
  
{
    
public edata(int a,int b,int c)
    
{
      
this.a=a;
      
this.b=b;
      
this.c=c;
    }

    
private int a;
    
private int b;
    
private int c;
    
public int A
    
{
      
get
      
{
        
return a;
      }

    }

    
public int B
    
{
      
get
      
{
        
return b;
      }

    }

    
public int C
    
{
      
get
      
{
        
return c;
      }

    }

  }

 
}

using System;
namespace equation5
{
  
/********************************************************/
  
//eqtion抽象出的操作方程类 //
  
//string X1 string X2 为求得的方程的两个根用out方式输出 //
  
//public eqtion() 既是类的构造函数又是方程求解的操作 //
  /************************************************/
  
public class eqtion
  
{
    
public eqtion(edata inData,out string X1,out string X2)
    
{
      
double dt;
      dt
=inData.B*inData.B-4*inData.A*inData.C;
      
bool bPlural=dt>=0?false:true;
      dt
=System.Math.Abs(dt);
      dt
=System.Math.Sqrt(dt);
      
double x1;
      
double x2;
      
if(bPlural)
      
{
        x1
=dt/2/inData.A;
        x2
=(0-inData.B)/2/inData.A;
        X1
=x2.ToString()+"+"+x1.ToString()+"i";
        x1
=0-x1;
        X2
=x2.ToString()+x1.ToString()+"i";
      }

      
else
      
{
        x1
=(dt-inData.B)/2/inData.A;
        x2
=(0-inData.B-dt)/2/inData.A;
        X1
=x1.ToString();
        X2
=x2.ToString();
      }

    }

  }

}

using System;
namespace equation5
{
  
/// <summary>
  
/// Class1 的摘要说明。
  
/// </summary>

  class Class1
  
{
    
/// <summary>
    
/// 应用程序的主入口点。
    
/// </summary>

    [STAThread]
    
static void Main(string[] args)
    
{
      
string A;
      
string B;
      
string C;
      
int a;
      
int b;
      
int c;
      System.Console.Write(
"Please input the modulus A = ");
      A
=System.Console.ReadLine();
      System.Console.Write(
"Please input the modulus B = ");
      B
=System.Console.ReadLine();
      System.Console.Write(
"Please input the modulus C = ");
      C
=System.Console.ReadLine();
      
try
      
{
        a
=int.Parse(A);
        b
=int.Parse(B);
        c
=int.Parse(C);
      }

      
catch
      
{
        System.Console.WriteLine(
"Input error!!!");
        
return;
      }

      
string X1,X2;
      edata Opedata 
= new edata(a,b,c);
      eqtion Opeqtion 
=new eqtion(Opedata,out X1,out X2);
      System.Console.WriteLine(
"X1 = {0}",X1);
      System.Console.WriteLine(
"X2 = {0}",X2);
    }

  }

}


posted on 2006-08-12 15:48 kim 阅读(2341) 评论(4)  编辑 收藏 网摘 所属分类: 系统架构分析设计模式敏捷开发(Agile Development)C#编程

评论

#1楼 2006-08-13 15:13 islands      

谢谢,学习中~~~~~~~~~   回复  引用  查看    

#2楼 2006-08-13 16:12 笨笨      

其实OCP是针对整体来说的.

假如这是一个计算引擎,不只是计算一元二次方程的根,还要计算其它的.那么新的修改一定会影响到客户端的调用.也没有很好的尊寻开闭原则.
不如试着从一个更高的高度来考虑.
  回复  引用  查看    

#3楼 2006-08-13 19:19 Zhongkeruanjian      

这个例子也太牵强了,这些原则都是为了类的重用与变化。而你没有举出在没有
遵循OCP原则的情况下你的类无法适应变化的例子。反而会误导阅读者。

这里面的操作与数据分离,其实就是单一职责的原则了。而不是开-闭原则。
  回复  引用  查看    

#4楼 2006-08-13 23:03 xing      

敏捷软件开发那本书里说的好像OCP关键在于抽象类,是在一个派生类里修改(也就是扩展)不改基类的,怎么没有用继承呢?,偶是新手,还不太懂设计原则   回复  引用  查看    




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 475106




相关文章:

相关链接:

导航

统计

公告

中文: 罗江华
英文: KIM
职务: PL
工作地: 成都/新加坡/美国
MSN: ljhkim6@hotmail.com

---------------------------

我的微软MVP配置
我写/翻译的书



俱乐部:[cdproclub@gmail.com]
网站:http://www.cdpro.com.cn

与我联系

搜索

 

常用链接

留言簿

我参与的团队

随笔分类(202)

随笔档案(159)

文章分类(4)

文章档案(11)

相册

收藏夹(8)

创业

技术网站

我的好友

最新评论