今天继续总结《重构》这本书中的一个重构手法,Introduce Null Object。写这个手法是因为它确实很巧妙,在实际编程中经常会遇到这种情况,前人总结出来了这么一个经典的手法,当然还有由此手法扩展更普遍更经典的手法--Special Case。

  刚入行的时候,听“老人”给我讲,书是要越读越薄的。当时没什么感受,觉得“老人”在故弄玄虚。工作4年多来,发现看过不少书,烂熟于心的却是最初入门的那一本--郭天祥C51。买的是一本影印盗版书(在大学里嘛,那年大二),不停的翻,书都翻烂了。现在那本书也不知道去哪了,但C51的所有内容都清清楚楚了。学习是为了什么,无非是为了精进,为以后做准备嘛。

  扯远了,接下来半年的时间里,争取有时间就写写读书笔记吧。近几年看了好几本技术书籍,有些还看了好几遍。写下来的内容都是为了把学过的知识捋一遍。

  开始今天的内容吧,这个重构手法在一定的应用场景下很有用。先来看看其应用场景。

  重构前的主体代码:

  1 package com.nelson.io;
  2
  3 public class Site {
  4
  5     private Customer _customer;
  6
  7     public Customer getCustomer()
  8     {
  9         return _customer;
 10     }
 11
 12     public void setCustomer(Customer cus)
 13     {
 14         _customer = cus;
 15     }
 16
 17 }
 18
 19 class Customer
 20 {
 21     String _name;
 22     BillingPlan _billingplan;
 23     PaymentHistory _paymentHistory;
 24
 25     public String getName()    {return _name;}
 26
 27     public BillingPlan getPlan() {
 28         return _billingplan;
 29     }
 30
 31     public PaymentHistory getHistroy(){
 32         return _paymentHistory;
 33     }
 34
 35     public Customer(){
 36     }
 37
 38     public Customer(String name,BillingPlan bill,PaymentHistory pay){
 39         _name = name;
 40         _billingplan = bill;
 41         _paymentHistory = pay;
 42     }
 43 }
 44
 45 class BillingPlan
 46 {
 47     private int basicpay;
 48     private int extrapay;
 49
 50     public BillingPlan(){
 51         setBasicpay(0);
 52         setExtrapay(0);
 53     }
 54
 55     public BillingPlan(int pay)
 56     {
 57         setBasicpay(pay);
 58         setExtrapay(0);
 59     }
 60
 61     public BillingPlan(int basic,int extra)
 62     {
 63         basicpay = basic;
 64         extrapay = extra;
 65     }
 66
 67     static BillingPlan basic()
 68     {
 69         return new BillingPlan(100);   //最低消费100元
 70     }
 71
 72     public int getTotalExpand()
 73     {
 74         return basicpay+extrapay;
 75     }
 76
 77     int getExtrapay() {
 78         return extrapay;
 79     }
 80
 81     void setExtrapay(int extrapay) {
 82         this.extrapay = extrapay;
 83     }
 84
 85     int getBasicpay() {
 86         return basicpay;
 87     }
 88
 89     void setBasicpay(int basicpay) {
 90         this.basicpay = basicpay;
 91     }
 92 }
 93
 94 class PaymentHistory
 95 {
 96     public int getWeeksDelinquentInLastYear;
 97
 98     public PaymentHistory()
 99     {
100         getWeeksDelinquentInLastYear = 0;
101     }
102 }

View Code

  重构前的应用代码:

 1 package com.nelson.io;
 2
 3 public class HelloWorld {
 4
 5     public static void main(String[] args) {
 6
 7         System.out.println("Hello Java!");
 8
 9         //不正常的客户
10         Site site = new Site();             //这样默认Site中的_customer = null
11         Customer cus1 = site.getCustomer();
12
13         String strName;
14         if(cus1 == null) strName = "occupant";   //顾客名字暂时叫做occupant
15         else strName = cus1.getName();   //获取用户的名字
16         System.out.println("Current Customer1: "+strName);
17
18         BillingPlan plan1;
19         if(cus1 == null) plan1 = BillingPlan.basic();
20         else plan1 = cus1.getPlan();
21         System.out.println("Total Expand:"+plan1.getTotalExpand());
22
23         //
24         //正常的客户
25         BillingPlan plan2 = new BillingPlan(100,19);
26         PaymentHistory history2 = new PaymentHistory();
27         Customer cus= new Customer("xiaoming",plan2,history2);
28         site.setCustomer(cus);
29
30         Customer cus2 = site.getCustomer();
31         if(cus2 == null) strName = "occupant";      //顾客名字暂时叫做occupant
32         else strName = cus2.getName();              //获取用户的名字
33         System.out.println("Current Customer2: "+strName);
34
35         if(cus2 == null) plan1 = BillingPlan.basic();
36         else plan1 = cus2.getPlan();
37         System.out.println("Total Expand:"+plan1.getTotalExpand());
38
39     }
40
41 }

View Code

在这里的重构要解决的问题是,应用代码中会不断的查询Site中的customer对象是否为空,这个应用的关键也在于允许customer=null的情况(这种情况存在不算错,而且必须应对这种情况)。Introduce Null Object手法就是去掉这里的重复查询是否为空的代码。

  重构后的主体代码:

  1 package com.nelson.io;
  2
  3 public class Site {
  4
  5     private Customer _customer;
  6
  7     public Customer getCustomer()
  8     {
  9         return (_customer==null)?Customer.newNull():_customer;
 10     }
 11
 12     public void setCustomer(Customer cus)
 13     {
 14         _customer = cus;
 15     }
 16
 17 }
 18
 19 class Customer implements Nullable
 20 {
 21     String _name;
 22     BillingPlan _billingplan;
 23     PaymentHistory _paymentHistory;
 24
 25     public String getName()    {return _name;}
 26
 27     public BillingPlan getPlan() {
 28         return _billingplan;
 29     }
 30
 31     public PaymentHistory getHistroy(){
 32         return _paymentHistory;
 33     }
 34
 35     protected Customer(){
 36     }
 37
 38     public Customer(String name,BillingPlan bill,PaymentHistory pay){
 39         _name = name;
 40         _billingplan = bill;
 41         _paymentHistory = pay;
 42     }
 43
 44     public static Customer newNull()
 45     {
 46         return new NullCustomer();
 47     }
 48
 49     public boolean isNull() {
 50         return false;
 51     }
 52 }
 53
 54 class NullCustomer extends Customer
 55 {
 56     public String getName()    {return "occupant";}
 57
 58     public BillingPlan getPlan() {
 59         return BillingPlan.basic();
 60     }
 61
 62     public boolean isNull() {
 63         return true;
 64     }
 65 }
 66
 67 class BillingPlan
 68 {
 69     private int basicpay;
 70     private int extrapay;
 71
 72     public BillingPlan(){
 73         setBasicpay(0);
 74         setExtrapay(0);
 75     }
 76
 77     public BillingPlan(int pay)
 78     {
 79         setBasicpay(pay);
 80         setExtrapay(0);
 81     }
 82
 83     public BillingPlan(int basic,int extra)
 84     {
 85         basicpay = basic;
 86         extrapay = extra;
 87     }
 88
 89     static BillingPlan basic()
 90     {
 91         return new BillingPlan(100);   //最低消费100元
 92     }
 93
 94     public int getTotalExpand()
 95     {
 96         return basicpay+extrapay;
 97     }
 98
 99     int getExtrapay() {
100         return extrapay;
101     }
102
103     void setExtrapay(int extrapay) {
104         this.extrapay = extrapay;
105     }
106
107     int getBasicpay() {
108         return basicpay;
109     }
110
111     void setBasicpay(int basicpay) {
112         this.basicpay = basicpay;
113     }
114 }
115
116 class PaymentHistory
117 {
118     public int getWeeksDelinquentInLastYear;
119
120     public PaymentHistory()
121     {
122         getWeeksDelinquentInLastYear = 0;
123     }
124 }
125
126 interface Nullable
127 {
128     boolean isNull();
129 }

View Code

  重构后的测试代码:

 1 package com.nelson.io;
 2
 3 public class HelloWorld {
 4
 5     public static void main(String[] args) {
 6
 7         System.out.println("Hello Java!");
 8
 9         //
10         //不正常的客户
11         Site site = new Site();            //这样默认Site中的_customer = null
12         Customer cus1 = site.getCustomer();
13         String strName = cus1.getName();   //获取用户的名字
14         System.out.println("Current Customer1: "+strName);
15         BillingPlan plan1 = cus1.getPlan();
16         System.out.println("Total Expand:"+plan1.getTotalExpand());
17
18         if(!cus1.isNull())
19             System.out.println("Customer1 is not null customer");
20         else
21             System.out.println("Customer1 is null customer");
22
23         System.out.println();
24
25         //
26         //正常的客户
27         BillingPlan plan2 = new BillingPlan(100,19);
28         PaymentHistory history2 = new PaymentHistory();
29         Customer cus= new Customer("xiaoming",plan2,history2);
30         site.setCustomer(cus);
31
32         Customer cus2 = site.getCustomer();
33         strName = cus2.getName();              //获取用户的名字
34         System.out.println("Current Customer2: "+strName);
35         cus2.getPlan();
36         System.out.println("Total Expand:"+plan1.getTotalExpand());
37
38         if(!cus2.isNull())
39             System.out.println("Customer2 is not null customer");
40         else
41             System.out.println("Customer2 is null customer");
42     }
43
44 }

View Code

  重构后的测试代码中,减少了对customer是否为null的判断。当测试代码中出现很多这样的判断时,此项重构价值得以体现。而且这样的好处还有,如果程序中碰到一个对象为null,不加判断去调用对象的函数,将造成程序崩溃。而将null的情况封装为Null Object后,将永不会出现这种异常。程序运行更安全。测试代码中的调用方只管使用方法就好了,保证不出错。注意Customer和NullCustomer中都实现了Nullable接口,意在告诉调用方有NullCustomer类存在。如果调用方实在想知道谁是NullCustomer谁是Customer,通过接口函数就可以知道了。

  引申的Special Case模式讲的就是特例模式,当SIte中的Customer = null时也算一种特例,当Customer中的name = “”时也是一种特例,也可以定义UnknownCustomer。或者种种其他的特殊情况--程序运行过程中大部分情况都是正常的Customer,但偶尔出现NullCustomer或者UnknownCustomer,Null Object和Special Case 保证程序能处理“极端”情况。

转载于:https://www.cnblogs.com/kanite/p/7679261.html

Introduce Null Object相关推荐

  1. Introduce Null Object(引入Null对象)

    Introduce Null Object(引入Null对象) 你需要再三检查某对象是否为null. 将null值替换为null对象. if (customer == null) plan = Bil ...

  2. Introduce Null Object(引入Null 对象)

    一而再,再而三地检查对象是否null public class Site {private Customer customer;public Customer getCustomer() {retur ...

  3. on a null object reference 问题的解决办法

    on a null object reference 问题的解决办法 参考文章: (1)on a null object reference 问题的解决办法 (2)https://www.cnblog ...

  4. android.content.Context.getResources()‘ on a null object reference

    super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); //开始运行时就把库先建好 //我在这边一开始 ...

  5. 使用Null Object设计模式[转]

    在ESFramework的设计实现中,很多地方都用到了Null Object设计模式.Null Object模式的含义在于,提供一个对象给指定的类型,用以代替这个对象为空的情况. Null Objec ...

  6. 被遗忘的设计模式——空对象模式(Null Object Pattern)

    一.Pattern name Provide an object as a surrogate for the lack of an object of a given type. The Null ...

  7. 重构--Introduce Parameter Object

    目录 1.Introduce Parameter Object概念 2.动机 3.案例 3.1. 实操 4.参考文献 1.Introduce Parameter Object概念 某个方法/函数的参数 ...

  8. setContentView报错NullPointerException: Attempt to invoke virtual method on a null object reference

    setContentView报错: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lan ...

  9. 解决Attempt to invoke virtual method '...ListAdapter'on a null object reference

    解决:Attempt to invoke virtual method 'voidAndroid.widget.GridView.setAdapter(android.widget.ListAdapt ...

最新文章

  1. float向u8和s8的转换
  2. 好骚气的树状数组的解释
  3. 算法-排序-冒泡排序
  4. iPictrue:图片标注提示
  5. 工具 转_好用的语音转文字工具,总有一款适合你!
  6. 3. LAMP 安装与配置
  7. vue用户行为收集_【用户行为采集】(一)常见埋点方式及对比
  8. burpsuite工具抓取Https数据包
  9. 银行测试汉字录入软件,小键盘数字练习软件(银行及各行业文员专用)
  10. 用android编写使用按钮ImageButton和切换器ImageSwitcher
  11. 基于JAVA飞羽羽毛球馆管理系统计算机毕业设计源码+数据库+lw文档+系统+部署
  12. 《密码编码学与网络安全》和《现代密码学》PDF
  13. stm32使用cubemx生成HAL库工程驱动mlx90614
  14. macBigSur使用mathtype数学公式编辑
  15. 数学建模·层次分析法基本步骤及参考代码
  16. 华为鸿蒙糸统其它手机可以用吗,鸿蒙系统vivo能用吗
  17. Android开发中虚拟位置定位、应用双开、IP代理检测
  18. WordPress更新文章实时推送到百度
  19. java读取csv文件的两种方式
  20. 测试集和训练集8:2切分

热门文章

  1. 格灵深瞳mysql面试三表联查
  2. 常用Linux命令大全(100%收藏食用❤️)
  3. android录音波浪动画_Android语音输入的波浪效果 – WaveView
  4. 手柄映射键盘_创新设计的多模手柄,北通宙斯T6精英机械游戏手柄体验点评
  5. Mac的自带软件grapher
  6. python实现外星人入侵——3.事件分析
  7. vue项目 如何解决浏览器缓存问题
  8. 1.1到底什么是云计算
  9. sockaddr,sockaddr_in,sockaddr_un结构体详细讲解
  10. echarts如何将柱形图的柱子分割成一小块一小块,也就是象形柱图