简单就是美——由模式谈面向对象的基本原则之单一职责原则

来源:互联网 发布:linux 上一个命令结果 编辑:程序博客网 时间:2024/04/27 14:44

                                                                        简单就是美
                                         ——由模式谈面向对象的基本原则之单一职责原则


     所谓单一职责原则,就是就一个类而言,应该仅有一个引起它的变化的原因。换句话说,一个类的功能要单一,只做与它相关的事情。
     这个原则是最简单、最容易理解,却是最不容易做到的事情。这个原则的道理谁都理解,可是在实践中呢?
     我们来看一个例子:
 if(action.equals("load")&&tab.equals("1")){
          request.setAttribute("tabId",tab);
          form.set("tabId",tab);
           speciManager.loadIncrement(actionForm, request, tab);
 }
 if(action.equals("Save")&&tab.equals("1")){
 System.out.println("inter increment save action");
 ……
 request.setAttribute("tabId",tab);
 }
 if(action.equals("load")&&tab.equals("2")){
          request.setAttribute("tabId",tab);
          form.set("tabId",tab);
           speciManager.loadMeasureMent(actionForm, request, tab);
 }
 if(action.equals("Save")&&tab.equals("2")){
    ……
          System.out.println("inter increment save action");
 speciManager.loadIncrement(actionForm, request, tab);
          form.set("tabId",tab);
          request.setAttribute("tabId",tab);
           
 }
     一看就知道这个类做了太多的工作,它既要load一个tab为1的页面和一个tab为2的页面;又要save一个tab为1页面和一个tab为2的页面。这个类的代码我只截取了里面很少的一部分,绝大部分的代码我都省略掉了。这段代码写到最后是越来越混乱,直到最后失败。
     对照着这个例子,我们再来分析一下为什么要遵守单一职责愿则:
    第一、有助于我们分析和编码的思路的清晰。当你的代码里有了三层或以上的if语句或for语句的嵌套的时候,你不要跟我说,你已经把问题分析得很清楚了。多层嵌套的if或for语句只能说明你还没有把问题分析清楚。
    第二、使我们的编码、测试和维护变得简单。
    第三、将一个个复杂的问题简单化以后,易于代码的重用。当你的代码的多个功能搅和在一起的时候,你是没办法考虑代码的重用的,因为你的每一处代码都有不同。
    第四、易于系统的扩展。
    好了,在这里一二三四的列举单一职责的原则不管用,我们需要看看实际的效果才好。现在我们就来看看模式是怎么来遵守这一原则的:
     首先,我们来看简单工厂模式。工厂类只有一个功能,就是产生一个个的对象产品。就这么一个简单的功能,但如果我们不把它拿出来,在客户端就会出现这样的代码:
 if(type.equals(“apple”))
 {
   Apple apple = new Apple();
   ……
 }
 else if(type.equals(“orange”))
 {
   Orange orange = new Orange(); 
   ……
 }
 else if(type.equals(“Banana”))
 {
   Banana banana = new Banana();
   ……
 }
     有了工厂,我们的客户端就变成这样:
 Fruit fruit = Factory.getInstance(type);
 ……
     我们的客户端调用起来多么的简单,而且系统扩展起来也与客户端无关。
     我们再来看模板方法模式。
 public abstract class Template {
  
  public void totalAction()
   {
    commonAction();
    differentAction();
   }
   private void commonAction()
   {
    //......
   }
   public abstract void differentAction();
 
 }
     这是一个模板类,它只做了一件事,就是所有子类的共同行为;然后去由它的子类单独完成自己的不同的行为。
     这样的蓄意让类的职责单一,拥有的好处是:第一、所有的子类的共同行为,只在模板类里构造一次,实现了代码的重用。第二、将各子类不同的行为分配到各子类里去,使得子类极为简单,易于实现。
     命令模式和策略模式的原理都相同,命令模式是对行为的封装,而策略模式是对算法的封装。两者都是要把相同的关注点和对他们的调用分离开,如命令模式是将行为和对它们的调用分离开,而策略模式是将算法和对它们的调用分离开。这里我们只以命令模式来说明问题。
 If(condition1)
 {
   //condition1下的行为
   doThing1();
 }
 else if(condition2)
 {
   //condition2下的行为
   doThing2();
 }
 else if(condition3)
 {
   //condition3下的行为
   doThing3();
 }
 ……
     命令模式可以方便的对上面的代码进行优化:
 public interface Common
 {
   public void doThing();
 }
 public class Common1 implements Common
 {
   public void doThing()
   {
    //condition1下的行为
    doThing1();
   }
 }
 public class Common2 implements Common
 {
   public void doThing()
   {
    //condition2下的行为
    doThing2();
   }
 }
 public class Common13implements Common
 {
   public void doThing()
   {
    //condition3下的行为
    doThing3();
   }
 
 }
 
     客户端:
 Common common;
 If(condition1) common = new Common1();
 else if(condition2) common = new Common2();
 else if(condition3) common = new Common3();
 common.doThing();
     命令模式通过将行为从调用者那里分离出来,达到了下面几个目的:第一,分离关注,对各个行为进行单独的关注,减少错误的出现。不管是对行为类还是它的调用者,都变得简单。第二,行为类通过对接口的实现,使得它们的调用者可以对它们进行动态绑定,增加了程序的灵活性和扩展性。
     代理模式将一个类的核心功能和它的附加功能区别开来,分别放在不同的类里面,从而使每一个类的功能更加单一。
 Public interface ProxyInterface
 {
   public void doing();
 }
 public class MainClass implements ProxyInterface
 {
   public void doing()
   {
    //core function
    ……
 }
 }
 public class ProxyClass implements ProxyInterface
 {
  private ProxyInterface core = new MainClass();
  public void doing()
  {
   //appending to do
   ……
   //main function
   core.doing();
 }
 }
     我们可以看到,通过代理模式,上面的MainClass类用来实现核心功能,而ProxyClass类用来实现附加功能,这样使得两个类的功能都非常简单,易于实现。
     总之,单一职责原则是一个既简单又实用的原则。我们遵守了这一原则,可能会多写一些类和代码,但磨刀不误砍柴工。该原则既有利于我们编码思路的清晰,又大大增强了代码的可维护性和扩展性。
     还等什么呢?