改善代码设计 —— 优“.NET技术”化物件之间的特性(Moving Features Between Objects)...

本文主要是介绍改善代码设计 —— 优“.NET技术”化物件之间的特性(Moving Features Between Objects)...,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  系列博客

      1. 改善代码设计 —— 优化函数的构成(Composing Methods)

      2. 改善代码设计 —— 优化物件之间的特性(Moving Features Between Objects)

      3. 改善代码设计 —— 组织好你的数据(Composing Data)

      4. 改善代码设计 —— 简化条件表达式(Simplifying Conditional Expressions)

      5. 改善代码设计 —— 简化函数调用(Making Method Calls Simpler)

      6. 改善代码设计 —— 处理概括关系(Dealing with Generalization)

  1. Move Method (函数搬家)

  解释:

        如果 ClassA 的某个函数对 ClassB 有过多的依赖, 可以考虑将这个函数搬到 ClassB 中, 在 ClassA 的这个函数中直接调用 ClassB中这个函数的返回值.

        这样做的好处是减少物件与物件之间的耦合度, 很多情况下这样做更利于进一步的重构.

  冲动前:

 
class EmployeeSalary
{
private double baseSalary = 15000.0 ;

public double Salary(Employee employee)
{
return baseSalary + 10000 / employee.Level;
}
// other method with baseSalary
}
class Employee
{
public int Level { get ; set ; }
}

  冲动后:

 
class EmployeeSalary
{
private double baseSalary = 15000.0 ;

public double Salary(Employee employee)
{
return employee.Salary(baseSalary);
}
// other method with baseSalary
}
class Employee
{
public int Level { get ; set ; }
public double Salary( double baseSalary)
{
return baseSalary + 10000 / Level;
}
}

  2. Move Field (值域搬家)

  解释:

      有一天发现公司原来计算员工工资的方法不合适了, 比如不是所有的员工起薪 (baseSalary) 都是一万五, 我想把 baseSalary 搬到 Employee 这个物件中作为员工的一个属性.

    &nb上海企业网站设计与制作sp; 这样做可使程序扩展性变得更好, 最明显的是我可以设置不同员工的起薪了.

  冲动前:

 
class EmployeeSalary
{
private double baseSalary = 15000.0 ;

public double Salary()
{
double 上海企业网站制作style="color: #000000;"> salary = baseSalary;
// do some compution with salary
return salary;
}
}

  冲动后:

 
class EmployeeSalary
{
public double Salary(Employee employee)
{
double salary = employee.BaseSalary;
// do some compution with salary
return salary;
}
}
class Employee
{
public double BaseSalary { get ; set ; }
}

  3. Extract Class (提炼类)

  解释:

      当某个物件做的事情过多, 这样的物件往往含有大量的字段, 属性和方法. 应该由两个或更多个物件来分担这些责任, 这时需要使用 Extract Class.

  冲动前:

 
class Employee
{
public double BaseSalary { get ; set ; }
public double Level { get ; set ; }

public double Salary()
{
double salary = BaseSalary;
// do some complex compution with salary
return salary;
}
}

  冲动后:

 
class EmployeeSalary
{
public double Salary(Employee employee)
{
double salary = employee.BaseSalary;
// do some complex compution with salary
return salary;
}
}
class Employee
{
public double BaseSalary { get ; set ; }
public double Level { get ; set ; }

public double Salary()
{
EmployeeSalary salary
= new EmployeeSalary();
return salary.Salary( this );
}
}

  4. Inline Class (将类内联)

  解释:

      Inline Class 和 Extract Class 正好相反. 当一个物件没有做它应该做的事情, 还专门使用了另一个物件来协助它完成这个职责, 这时可以考虑使用 Inline Class.

      如上面所示的例子, 如果我觉得 Employee 这个物件本身就应该实现 Salary 的计算工作, 而不是专门写一个 Salary 的计算物件来帮助它计算, 可以使用 Inline Class 将 Salary 内联到 Employee 中去, 也就是"冲动后"的代码重构成"冲动前"代码的样子.

  5. Hide Delegate (隐藏委托关系)

  解释:

      试想这么一个情况: 有一个 Employee 类, 这个类中含有一个部门 (Department) 属性, 并且 Department 是一种类. 如果我想知道某职工所在部门的经理人是谁的时候, 我需要通过 xxEmployee.Department.Manger 来访问. 但这样做有个缺点是对于其它代码,  Department 是 public 的, 其它代码能够访问到 Department 里的其它特性. 可以在 Employee 类中写一个 GetManger() 方法进行封装, 在调用的时候只需要xxEmployee.GetManger() 就行了.

  冲动前:

 
class Department
{
public string Manger { get ; set ; }
}
class Employee
{
public Department Department { get ; set ; }
}

  冲动后:

 
class Department
{
public string Manger { get ; set ; }
}
class Employee
{
private Department Department;

public string GetManger()
{
return Department.Manger;
}
}

  6. Remove Middle Man (干掉中间人)

  解释:

      这一条与上一条 Hide Delegate 是相反的. 当我们要访问 Department 的其它很多特性时, 我们用 Hide Delegate 写了一条条简单的委托访问函数, 当这些函数多到几乎访问遍了 Department 里的内容, 可以考虑使用 Remove Middle Man 方法将这些访问函数干掉.

      如上面的例子, 就是将"冲动后"的代码重构成"冲动前"代码的样子.

  7. Introduce Foreign Method (引入外加函数)

  解释:

      Introduce Foreign Method 有很深的 C#3.0 中扩展方法的味道, 但扩展方法比 Introduce Foreign Method 好在: 扩展方法就好象是被扩展的那个类型自己的方法一样, 而 Introduce Foreign Method 的函数还需要传递这个类型的参数, 但其实编译器编译扩展方法后还是会把参数传进去的, 扩展方法只是一种语法糖.

      它的主要目的是实现被调用的类中没有实现的功能, 注意在进行本项重构时, 如果引入一个外加函数, 这说明这个函数本应该在被调用的类中实现. 下面举一个简单到不能再简单的例子, 这个例子只是说明怎么使用 Introduce Foreign Method, 我并不是说 Int32类型就应该有一个 NextNum 的方法 , 并且实际中多数情况下这种重构用于引用类型微笑

  冲动前:

 
int num = 1 ;
// I want to get num's next
int nextNum = num + 1 ;

  冲动后:

 
int num = 1 ;
int nextNum = NextNum(num);

private static int NextNum( int arg)
{
return arg + 上海网站建设tyle="color: #000000;"> 1 ;
}

  8. Introduce Local Extension (引入本地扩展)

  解释:

      如果我不想使用 Introduce Foreign Method, 我觉得它就本来应该实现某某功能, 如果被调用的类不是密封 (sealed) 的话, 可以自定义一个数据类型, 继承这个类, 在自己定义的数据类型中实现我想要它实现的功能, 这就是 Introduce Local Extension.

转载于:https://www.cnblogs.com/waw/archive/2011/10/13/2210647.html

这篇关于改善代码设计 —— 优“.NET技术”化物件之间的特性(Moving Features Between Objects)...的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/352278

相关文章

SpringBoot3.4配置校验新特性的用法详解

《SpringBoot3.4配置校验新特性的用法详解》SpringBoot3.4对配置校验支持进行了全面升级,这篇文章为大家详细介绍了一下它们的具体使用,文中的示例代码讲解详细,感兴趣的小伙伴可以参考... 目录基本用法示例定义配置类配置 application.yml注入使用嵌套对象与集合元素深度校验开发

利用Python调试串口的示例代码

《利用Python调试串口的示例代码》在嵌入式开发、物联网设备调试过程中,串口通信是最基础的调试手段本文将带你用Python+ttkbootstrap打造一款高颜值、多功能的串口调试助手,需要的可以了... 目录概述:为什么需要专业的串口调试工具项目架构设计1.1 技术栈选型1.2 关键类说明1.3 线程模

Python Transformers库(NLP处理库)案例代码讲解

《PythonTransformers库(NLP处理库)案例代码讲解》本文介绍transformers库的全面讲解,包含基础知识、高级用法、案例代码及学习路径,内容经过组织,适合不同阶段的学习者,对... 目录一、基础知识1. Transformers 库简介2. 安装与环境配置3. 快速上手示例二、核心模

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码

《Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码》:本文主要介绍Java中日期时间转换的多种方法,包括将Date转换为LocalD... 目录一、Date转LocalDateTime二、Date转LocalDate三、LocalDateTim

jupyter代码块没有运行图标的解决方案

《jupyter代码块没有运行图标的解决方案》:本文主要介绍jupyter代码块没有运行图标的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录jupyter代码块没有运行图标的解决1.找到Jupyter notebook的系统配置文件2.这时候一般会搜索到

golang获取当前时间、时间戳和时间字符串及它们之间的相互转换方法

《golang获取当前时间、时间戳和时间字符串及它们之间的相互转换方法》:本文主要介绍golang获取当前时间、时间戳和时间字符串及它们之间的相互转换,本文通过实例代码给大家介绍的非常详细,感兴趣... 目录1、获取当前时间2、获取当前时间戳3、获取当前时间的字符串格式4、它们之间的相互转化上篇文章给大家介