设计模式(二)- 建造者模式 /反射+抽象工厂

toc

好久没发动态了,基于这端时间一只忙于经销商的开发,现在终于有了一些空余时间。这次继续上次设计模式,继续写我的笔记。。。。。。

#建造者模式

建造者模式(Builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程就可以创建不同的表示。

建造者模式又称为“生成器模式”,建造者模式可以将一个产品的内部表象与产品的生产过程分割开来,从而可以使一个建造过程生成具有不同的内部产品对象。当使用建造者模式,那么用户就只需要指定需要建造的类型就可以得到它们,而不就不需要知道具体建造的过程和细节。

#代码体现

/**
 * 产品类
 */
public class Product {
    List<String> parts = new ArrayList<>();

    public void add(String part) {
        parts.add(part);
    }
    
    public void show() {
        for (int i = 0, length = parts.size(); i < length; i ++) {
            System.out.println("=============part========== "+parts.get(i));
        }
    }
}

/**
 * 抽象建造者类
 */
public abstract class Builder {
    public abstract void buildPartA();
    public abstract void buildPartB();
    public abstract Product getResult();
}

/**
 * 具体建造者1
 */
public class BuilerOne extends Builder {
    
    private Product product = new Product();
    
    @Override
    public void buildPartA() {
        product.add("A部件");
    }

    @Override
    public void buildPartB() {
        product.add("B部件");
    }

    @Override
    public Product getResult() {
        return product;
    }
}

/**
 * 具体建造者2
 */
public class BuilderTwo extends Builder {
    
    private Product product = new Product();
    
    @Override
    public void buildPartA() {
        product.add("C部件");
    }

    @Override
    public void buildPartB() {
        product.add("D部件");
    }

    @Override
    public Product getResult() {
        return product;
    }
}

/**
 * 指挥者类
 */
public class Director {
    public void construct(Builder builder) {
        builder.buildPartA();
        builder.buildPartB();
    }
}

/**
 * 客户端
 */
public class ClientA {
    public static void main(String[] args) {
        Director director = new Director();
        Builder b1 = new BuilerOne();
        Builder b2 = new BuilderTwo();

        director.construct(b1);
        Product product1 = b1.getResult();
        product1.show();

        director.construct(b2);
        Product product2 = b2.getResult();
        product1.show();
    }
}

运行结果:

image.png

建造者主要用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。优点:使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义个具体的建造者就可以了。

image.png

总结:建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式适用的模式。

#抽象工厂模式

抽象工厂模式:提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类。

以平常最简单的开发为例,在开发中我们经常会用到持久化的框架(mybatis,hibernate 等)连接相应的数据库,当没有抽象工厂模式,我们写的代码会很“丑”,一旦切换数据库修改起来就会十分繁琐。当我们使用了抽象模式就会减轻很多的负担。

#反射+抽象工厂模式的数据访问程序

/**
 * 部门表domain类
 */
public class Department {
    private int id;
    private String deptName;
}

public interface IDepartment {
    void insert(Department department);
    
    Department getDepartment(int id);
}

/**
 * 模拟访问sql server 
 */
public class SqlserviceDepartment implements IDepartment {
    public void insert(Department department) {
        System.out.println("add a data in sql server DB!");
    }

    public Department getDepartment(int id) {
        System.out.println("show a data by id in sql server!");
        return null;
    }
}

/**
 * 模拟访问Access
 */
public class AccessDepartment implements IDepartment {
    public void insert(Department department) {
        System.out.println("add a data in Access DB!");
    }

    public Department getDepartment(int id) {
        System.out.println("show a data by id in Access DB!");
        return null;
    }
}

/**
 * 访问Department表对象的抽象的工厂借口
 */
public interface IFactory {
    IDepartment createDepartment();
}

/**
 * 实现IFactory接口,实例化SqlServerDepartment
 */
public class SqlServerFactory implements IFactory{
    public IDepartment createDepartment() {
        return new SqlserviceDepartment();
    }
}

/**
 * 实现IFactory接口,实例化AccessDepartment
 */
public class AccessFactory implements IFactory{
    public IDepartment createDepartment() {
        return new AccessDepartment();
    }
}

public class Client {
    public static void main(String[] args) {
        Department department = new Department();
        IFactory iFactory = new SqlServerFactory();
        IDepartment iDepartment = iFactory.createDepartment();
        iDepartment.insert(department);
    }
}

上述代码中如果将SqlServer切换为Access数据库连接,需修改new SqlServerFactory()->new AccessFactory();但当我们引用的地方太多的时候,修改起来还是比较麻烦的。这是用反射就可以完美解决

public class DataAccess {
    //数据库连接包名
    private static String dataName = "abstractModle.SqlServerFactory";
    
    public static IDepartment  createDepartment() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        return (IDepartment) Class.forName(dataName).newInstance();
    }
}
image.png

上述中如果要切换数据库,需要修改dataName的名称,需要重新编译,在不修改程序的情况下可以,添加数据库连接信息的配置,通过读取配置信息的方法读取变量值,这样切换时就只需要修改配置文件值,不需重新编译代码了,耦合度大大降低。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ThoughtWorks

在项目中透明地引入特性开关

之前曾经推荐过崔立强的《使用功能开关更好地实现持续部署》,介绍Feature Toggle的实践。北京办公室的孟宇现在对这个问题有了新的思考,当我们抛却Spri...

3436
来自专栏aCloudDeveloper

防御性编程

Author:bakari       Date:2012.8.25 本篇是我根据网上的一些陈述经过整理和总结而得。其中详细的内容我会标注出处。看不懂的可以查看...

2318
来自专栏小樱的经验随笔

BugkuCTF 计算器

前言 写了这么久的web题,算是把它基础部分都刷完了一遍,以下的几天将持续更新BugkuCTF WEB部分的题解,为了不影响阅读,所以每道题的题解都以单独一篇文...

26310
来自专栏轮子工厂

如果你想学好Python,这几本书说不定可以帮助到你哦

652
来自专栏牛客网

阿里技术一面,Java研发岗

之前过了个简单的简历面,过了几天后没打来以为凉了,然后昨晚又接到了电话,括号内容是回答说的,理解有限,不一定都对,欢迎纠正~加油每一个牛友们! 阿里一面: ...

4389
来自专栏坚毅的PHP

HBase client访问ZooKeeper获取root-region-server DeadLock问题(zookeeper.ClientCnxn Unable to get data of zn

2012年11月28日 出现故障," Unable to get data of znode /hbase/root-region-server" 问题比较诡异...

5264
来自专栏落影的专栏

AUGraph结合RemoteI/O Unit与Mixer Unit

前言 相关文章: 使用VideoToolbox硬编码H.264 使用VideoToolbox硬解码H.264 使用AudioToolbox编码AAC 使...

4869
来自专栏BeJavaGod

BeJavaGod - 如何正确使用数据字典进行分类统一操作(一)

先说说什么是数据字典,这个玩意一般不太会解释,举个栗子吧~ 每个系统都会有用户表,性别:男(1)女(0) 另外我们做物流的会涉及到车型:卡车(1),轿车(2),...

3287
来自专栏编程

Sprint测试交付物设计

交付物定义: 基于敏捷开发流程,每个Sprint周期交付内容应如下: Burndown Chat(燃尽图),例如下图所示: ? Smock Test(冒烟测试)...

2066
来自专栏liulun

Nim教程【一】

这应该是国内第一个关于Nim入门的系列教程 什么是Nim 我们先来引述网友 Luikore的一段话: Nim 不是函数式的, 但 ...

3179

扫码关注云+社区