【BlankFox学习笔记-重构与模式】趋向Factory的重构——针对创建对象部分重构代码

趋向Factory的重构

笔记版本:1.0
作者:BlankFox(CSDN主页)
归档:重构与模式

写在前面:

ps: 重构是针对现有代码的重新构建,使得其更易于理解、扩展以及修改,在重构的过程中不能凭感觉修改代码,这会导致很多问题——重构后代码不能运行、代码更复杂、代码产生新的需要重构的部分。因此,代码重构需要一些发现问题的方法指导,以及规定一些大致步骤,循序渐进,逐步测试。

ps:在既有代码中,一定存在很多创建对象的内容,优秀的代码会很清晰的告诉代码读者——创建了什么对象,而不是让读者去了解其中的构造函数细节——如果代码中出现了许多同名构造函数-使用重构以创建方法封装、如果出现了多个构建方法使得原类的职责不清晰-使用重构提取创建方法包装成简单工厂、出现了类似函数但其中有不同的创建对象方法-使用重构趋向工厂方法

一、代码问题

首先确定问题,才能知道哪个地方可以优化

错 误 示 例 . 1 — — 太 多 的 同 名 构 造 函 数 \color{red}{错误示例.1——太多的同名构造函数} .1

//错误示例.1——太多的同名构造函数
/* 创建一个描述账单的类,该类有多个字段,多个构建函数对应不同的账单 */
class Bill{
    
    
    /* 全构造函数(包含所有参数) */
    public Bill(int id,String name,Type type,int money,Date date,String owner,...){
    
    ...}
    /* 构造一个普通账单,id以及date等都自动分配 */
    public Bill(String name,Type type,int money){
    
    ...}
    /* 构造一个特殊支出账单,表示该支出是持久的 */
    public Bill(String name,int money,Type specialType){
    
    }//这里故意将位置调整一下,模拟错误
    ...
    //more public Bill(){}
}

class Client{
    
    
    public void useBill(){
    
    
        /* 该怎么构建Bill呢? 这要求使用者熟悉Bill构建详细内容 */
        Bill bill=new Bill(???);
    }
}

该问题可以归类为代码难以理解中,使用简化重构——其核心思想是使得代码更好读懂,结构更合理,方法之一是使用创建方法封装同名构造函数——详解示例.1——使用创建方法封装

错 误 示 例 . 2 — — 创 建 职 责 过 多 且 分 散 \color{red}{错误示例.2——创建职责过多且分散} .2

//错误示例.2——创建职责过多且分散
/* 稍微改进上一个错误示例,简单封装实现了自我工厂(自己负责自己创建) */
class Bill{
    
    
    /* 全构造函数(包含所有参数) */
   	private Bill(int id,String name,Type type,int money,Date date,String owner,...){
    
    ...}
    /* 构造一个普通账单,id以及date等都自动分配 */
    public static Bill defaultBill(String name,Type type,int money){
    
    ...}
    /* 构造一个特殊支出账单,表示该支出是持久的 */
   	public static Bill staticOutBill(String name,Type specialType,int money){
    
    }//这里故意将位置调整一下,模拟错误
    ...
    //more public static Bill XXXBill(){}——这里你可以创建一些Bill的子类实现更多的功能
}
/* 尽管现在我们将创建函数名称和创建出的Bill描述结合起来了,但是过多的创建函数占用了Bill太多内容,而且static函数?不是很有必要呆在Bill中,这不应该是它的责任 */

过多的创建职责——使得你的类就像钞票能够负责自己印刷不同面额一样奇怪 ,很容易想到的是使用一个 简单工厂负责创建功能——见示例.2——使用工厂集中创建职责

错 误 示 例 . 3 — — 相 同 逻 辑 的 重 复 \color{red}{错误示例.3——相同逻辑的重复} .3

//错误示例.3——相同逻辑的重复
class RootNodeTest{
    
    
    public void showRootTest(){
    
    
        /* 处理代码中创建部分不同之外,其余部分大致相同 */
        Node node=new Root();
        
        node.addChild("next1");
        node.addChild("next2");
        //do other sameWork
        
        node.show();//使用root的show测试结果
    }
}

class NomalNodeTest{
    
    
    public void showNodeTest(){
    
    
        
        Node node=new NomalNode();
        
        node.addChild("next1");
        node.addChild("next12");
        //do other sameWork
        
        node.show();//使用nomalNode的show测试
    }
}

过多的重复工作使得代码复用性不高,而且增大了理解每个部分的成本,可以使用Factory Method方法求同存异,提取公共部分到父类,使得子类去实现具体的创建方法

二、对应的重构方法

示 例 . 1 — — 使 用 创 建 方 法 “ 重 命 名 ” 同 名 构 造 方 法 \color{green}{示例.1——使用创建方法“重命名”同名构造方法} .1使

//示例.1——使用创建方法“重命名”同名构造方法
/* 对于一个简单的类,多个同名的构造方法使得其使用不便,使用创建方法为构造函数加以描述 */
class Bill{
    
    
    private final int id;
    ...
    
    public static Bill creatBillByMoney(int i){
    
    
        /* 使用创建方法包装了很多默认构造选项,使得使用更方便,而且名字更具体 */
        return new Bill(getId(),"默认",TYPE.DEFAULT,getDate(),i);
    }
    
    public Bill(int id,String name,Type type,Date date,int money){
    
    ...}
    
    ...
}

class Client{
    
    
    public void use(){
    
    
        //Bill b=new Bill(getId(),"默认",TYPE.DEFAULT,getDate(),i);
        Bill b=creatBillByMoney(100);
    }
}

示 例 . 2 — — 使 用 简 单 工 厂 统 一 对 象 创 建 职 责 \color{green}{示例.2——使用简单工厂统一对象创建职责} .2使

//示例.2——使用简单工厂统一对象创建职责
class BillFactory extend Factory{
    
    
    public Bill creatBillByMoney(...){
    
    ...};
    public Bill creatBillWithTag(...){
    
    ...};
    //...
    
    /* 封装一些细节处理方法帮助创建对象,这部分功能不应该在原类中提炼 */
    private boolean dealDetails(...){
    
    ...};
    //...
}

示 例 . 3 — — 使 用 工 厂 方 法 提 取 共 有 代 码 , 保 留 多 态 创 建 \color{green}{示例.3——使用工厂方法提取共有代码,保留多态创建} .3使

//示例.3——使用工厂方法提取共有代码,保留多态创建
abstract class NodeTest{
    
    
    public void showNodeTest(){
    
    
        
        Node node=creatNode();
        
        node.addChild("next1");
        node.addChild("next2");
        //do other sameWork
        
        node.show();//使用nomalNode的show测试
    }
    
    abstract Node creatNode();
}

/* 省去了重复写一大堆逻辑代码,只需要关注其不同的部分即可,下面两个类都相当于一个简单工厂类 */
class RootNodeTest extend NodeTest{
    
    
   	@Override
    public Node creatNode(){
    
    
        return new RootNode();
    }
}

class NomalNodeTest extend NodeTest{
    
    
    @Override
    public Node creatNode(){
    
    
        return new NomalNode();
    }
}


三、重构图示

在这里插入图片描述

重构步骤:

  1. 找到多个同名构造函数职责不清晰、或者构造过程长的代码
  2. 创建方法封装构造函数,提炼相同逻辑
  3. 根据需要(创建方法过多,原类不需要承担构造职责),提炼出简单工厂类
  4. 如果存在多个工厂,且部分处理逻辑相同,提炼出工厂方法类

四、问题回顾

1. 主 要 应 用 场 景 ? \color{blue}{1.主要应用场景?} 1.

答:重点关注创建对象时,如果同名构造函数过多不利于使用-使用创建函数包装,如果创建任务职责不当-使用工厂类集中创建职责,如果创建对象的处理方法重复-提取工厂方法类

2. 一 定 需 要 重 构 吗 ? \color{blue}{2.一定需要重构吗?} 2.

答:重构的目的是简化理解和代码易扩展,如果完全没有扩展需求或者代码体量很小,比如不必为了一个创建职责而单独包装一个工厂类。但是如果重复代码,过多的对象创建导致了你的代码臃肿不堪,难以理解——不要犹豫,立刻开始重构,不要使得问题越来越多

3. 重 构 以 趋 向 或 实 现 F a c t o r y 模 式 有 什 么 帮 助 ? \color{blue}{3.重构以趋向或实现Factory模式有什么帮助?} 3.Factory

答:使得对象构建易于理解,构建与使用解耦(修改对象的创建过程不会导致使用对象的代码大量修改);使得职责划分更合理,钞票不会自己负责印刷自己;解决部分由于构建不同对象的代码重复问题

欢迎关注我、共勉⭐️

⭐️⭐️代码之狐⭐️⭐️
主要内容:

  • 时不时更新算法题解,算法与数据结构
  • 时不时分享心灵鸡汤,详见杂谈栏
  • 目前主要在学Java高级内容(虚拟机、框架什么的),以及很重要的软件工程、重构和设计模式等,会将书中的知识点提炼总结分享

猜你喜欢

转载自blog.csdn.net/caqjeryy/article/details/124403529