zoukankan      html  css  js  c++  java
  • 引入间接隔离变化(一)

    David Wheeler有一句名言:“计算机科学中的大多数问题都可以通过增加一层间接性来解决。”间接代表着迂回。世间没有哪一条道路是完全笔直的。蜿蜒曲折的道路并非出于美的灵感,不过是因为我们需要绕开路途中的障碍罢了。

    我们在设计中遇到的最大障碍,无疑就是变化。若能御变化于实现之外,软件开发就会变得美好。

    应对变化的要诀是隔离。设计者需要界定对象的不变部分与可变部分,然后将可变部分隐藏起来,即使发生了变化,也不会影响到外部。这就是封装的含义。正如地壳核心的变化如此的狂暴与迅捷,但对于地面上生活的人类而言,几乎微不可察。然而,一旦地壳的变化冲出地表,就会酿成天大的灾难。变化对软件系统造成的灾难,并不亚于地震或者火山。封装为对象内部的实现设定了一层隔离带,将复杂变化的业务逻辑或者算法策略隐藏在对象之内。只要保证对象的接口不发生变化,调用者与对象内部的实现就可以单独演化了。

    当我们发现一个对象需要依赖另一个不稳定的对象,同时,还需要执行复杂的交互逻辑时,就可以考虑引入一个新的对象来封装这些逻辑,从而解除二者之间的耦合,隔离变化。Spring MVC中的ModelAndView对象扮演的正是这一角色。根据MVC模式,控制器需要将模型对象所持有的数据以及数据的变化呈现到视图中。它通过寻找正确的视图对象,完成页面的展现。控制器承担了这一职责,就意味它必须依赖于视图对象。例如这样的代码:

    public class CustomerController implements Controller {
        @Override
        public View handleRequest(
                HttpServletRequst request,
                HttpServletResponse response) throws Exception {
            Map model = new HashMap();
            model.put(“customers”, getCustomerList());
            return new InternalResourceView(”/WEB-INF/jsp/customerList.jsp”);
        }
    }

    View具体对象的创建,使得CustomerController与InternalResourceView紧紧地绑定起来,失去了灵活性,导致我们无法自由改变View的实现。作为一个灵活的MVC框架,显然很难容忍这二者之间的强耦合。要打破这种耦合关系,就需要封装寻找以及创建视图的职责,并将这一职责放到合适的对象中。这正是引入ModelAndView类的缘由。Controller放心地将所有与View相关的职责转移给ModelAndView,而它只需要悠闲地传递一个视图名称即可。

    public class CustomerController implements Controller {
        @Override
        public ModelAndView handleRequest(
                HttpServletRequst request,
                HttpServletResponse response) throws Exception {
            Map model = new HashMap();
            model.put(“customers”, getCustomerList());
            return ModelAndView(”customerList”, model);
        }
    }

    通过字符串类型的名称常量去寻找合适的视图,而不是具体的View对象,就使得Controller冲破了View类型的约束,变得自在而开放。因为封装的作用,Controller对象变得无知,然而,“无知者无畏”,它也不用害怕视图呈现所发生的变化了。image 隔离变化的另一条途径是寻觅对象的共性,对这些共性进行抽象。我们不必考虑对象实现细节的不同之处,只需要把握对象的共同特征,即可完成接口的定义。接口可以看做是对象的角色。Rebecca认为:“客户访问接口比访问具体类要灵活得多,它们不需要知道具体实现,而只需明了接口中声明的公共角色即可。”【注:Rebecca Wirfs-Brock《对象设计:角色、责任和协作》】角色代表一种功能或职责的扮演,它并非演员本身,只是形象化地以某种形态或语言来表现角色的喜怒哀乐而已。例如,我们需要在项目中指定规则以限定渲染的格式。这个规则可以是数据区间,只要数据在这个区间范围之内,就应该设置为对应的格式;也可以是某种约束条件,当条件满足时,以相应的格式渲染。从实现细节来看,区间与约束是迥然不同的两种实现;可是从抽象的角度看,它们无疑扮演的都是同一种角色,那就是匹配器。只要规则匹配,就应该获得正确的格式。image public interface Matcher {
        public boolean matches(Object value);
    }

    public class Range implements Matcher{
        private double min;
        private double max;
        public Range(double min, double max) {
            this.min = min;
            this.max = max;
        }
        private boolean in(double data) {
            //判断data是否在此区间
        }

        public boolean matches(Object value) {
            try {
                return in((double)value);
            }catch (InvalidCastException) {
                return false;
            }
        }
    }

    public class Constraint implements Matcher {
        private String expected;
        private boolean ignoreCase;
        public Constraint(String expected) {
            this.expected = expected;
            ignoreCase = true;
        }

        public Constraint(String expected, boolean ignoreCase) {
        }
        public boolean matches(Object value) {
            if (ignoreCase) {
                return expected.equalsIgnoreCase(value.toString());
            } else {
                return expected.equals(value.toString());
            }
        }
    }

    Matcher接口抽象了区间与约束的共性特征,使得二者在规则中能够友好相处:
    public class Rule {
        public Rule(Matcher matcher, Format format){}
        public Matcher getMatcher(){}
        public void setMatcher(Matcher matcher){}
        public Format getFormat(){}
        public void setFormat(Format format){}
    }

    如果需要更多的匹配器,只要实现Matcher接口,就可以放入Rule中,作为格式规则的一部分。这种包容变化的能力,正是抽象能够提供的。

  • 相关阅读:
    软件架构设计模式简述
    [翻译]docker生态圈Mindmap
    完美解决Invalid layout of java.lang.String at value问题的方法
    用开源项目JazzyViewPager实现ViewPager切换动画
    用开源项目RangBar来实现有范围的SeekBar
    开源项目MultiChoiceAdapter详解(六)——GridView和MultiChoiceBaseAdapter配合使用
    开源项目MultiChoiceAdapter详解(五)——可扩展的MultiChoiceBaseAdapter
    开源项目MultiChoiceAdapter详解(四)——MultiChoiceBaseAdapter的使用
    开源项目MultiChoiceAdapter详解(三)——MulitChoiceNormalArrayAdapter的使用
    开源项目MultiChoiceAdapter详解(二)——MultiChoiceArrayAdapter的使用
  • 原文地址:https://www.cnblogs.com/wayfarer/p/1935185.html
Copyright © 2011-2022 走看看