设计原则-合成复用原则

Posted namelessmyth

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计原则-合成复用原则相关的知识,希望对你有一定的参考价值。

简介

  • 定义:尽量使用对象组合/聚合,而不是继承关系达到软件复用的目的。
  • 聚合has-A和组合contains-A。
  • 优点:可以使系统更加灵活,降低类与类之间的耦合度,一个雷的变化对其他类造成的影响相对较少。

继承复用虽然简单,但是存在很大的缺点:
 (1)耦合度高,父类代码的修改会影响到子类,不利于代码的维护。
 (2)破坏了类的封装性,因为继承会将父类的实现细节暴露给子类,所以又叫做 “白箱” 复用。
 (3)限制了复用的灵活性,从父类继承来的实现是静态的,在运行期是无法改变的。

合成复用是将已有的对象作为新对象的成员对象来实现,新对象调用已有对象的功能,达到复用:
 (1)不会破坏封装性,因为新对象只能调用已有对象暴露出来的方法,所以又叫做 “黑箱” 复用
 (2)耦合度低,已有对象的变化对新对象的影响较小,可以在新对象的中,根据需要调用已有对象的一些操作。
 (3)复用的灵活性高,可以在代码的运行中,动态选择相同类型的其他具体类。

实现参考

先看通过继承来复用的案例。

/**
* 数据库链接类,目前只有mysql。
*/
public class DBConnection 
    public String getConnection() 
        return "MySQL数据库连接";
    


/**
* 通过继承来使用工具类的方法。后面如果改成Oracle了,需要修改代码。而且改了之后还会影响老功能。
*/
public class ProductDao extends DBConnection

    public void addProduct()
        String conn=super.getConnection();
        System.out.println("使用"+conn+"增加产品");
    


/**
* 客户端使用
*/
public class CompositionAggregationTest 
    public static void main(String[] args) 
        ProductDao productDao = new ProductDao();
        productDao.addProduct();
    

改成合成的方式复用。

/**
* 数据库链接类,改成抽象类,后面用不同的数据库实现类来继承他。
*/
public abstract class DBConnection 
    public abstract String getConnection();


public class MySQLConnection extends DBConnection
    @Override
    public String getConnection() 
        return "MySQL数据库连接";
    


public class PostgreSQLConnection extends DBConnection
    @Override
    public String getConnection() 
        return "PostgreSQL数据库连接";
    


/**
* 通过成员变量合成复用。
*/
public class ProductDao 
    private DBConnection dbConnection;

    public void setDbConnection(DBConnection dbConnection) 
        this.dbConnection = dbConnection;
    

    public void addProduct() 
        String conn = dbConnection.getConnection();
        System.out.println("使用" + conn + "增加产品");
    


public class CompositionAggregationTest 
    public static void main(String[] args) 
        ProductDao productDao = new ProductDao();
        productDao.setDbConnection(new PostgreSQLConnection());
        productDao.addProduct();
    

设计模式软件设计七大原则 ( 合成复用原则 | 代码示例 )





一、合成复用原则简介



合成复用原则 又称为 组合复用原则 , 合成/聚合复用原则 , 组合/聚合复用原则 ;


合成复用原则定义 : 想要达到 软件复用 的目的 , 尽量使用 对象 组合/聚合 , 而不是 继承关系 ;


聚合 是 has-A 关系 ; ( 关系较弱 ) 代表部分事物的对象 ( 次 )代表聚合事物的对象 ( 主 ) 生命周期无关 , 删除了聚合对象 , 不代表删除了代表部分事物的对象 ;

组合 是 contains-A 关系 ; ( 关系较强 ) 一旦删除 代表组合事物的对象 ( 主 ) , 那么 代表部分事物的对象 ( 次 ) 也一起被删除 ;

继承 是 is-A 关系 ;


电脑 与 U 盘 是聚合关系 , 电脑没了 , U 盘可以独立存在 , 还可以接在其它电脑上 ;


A 类中包含了 B 类的引用 , 当 A 类对象销毁时 , B 类引用所指向的对象也一同消失 , 没有任何一个引用指向他 , 该引用成为了垃圾对象 , 被回收 ; 这种情况就是 组合 ;

加入 A 类销毁后 , B 类对象还有在其它位置被引用 , B 类对象不会被销毁 , 此时这种关系就是 聚合 ;





二、合成复用 与 继承复用 优缺点




合成复用优点 : 使系统 更加灵活 , 降低 类与类 之间的耦合度 , 一个类的变化对其他类造成的影响相对较少 ;

合成复用缺点 : 通过 组合 / 聚合 方式建造的系统 , 有较多的对象需要管理 ;


继承复用优点 : 扩展性容易实现 , 继承父类后 , 父类的所有功能都可以通过继承关系进入子类 , 修改和扩展都比较容易 ;

继承复用缺点 : 破坏包装 , 继承将父类的实现细节暴露给了子类 , 这种复用称为白箱复用 ;


继承复用 称为 白箱复用 , 组合 / 聚合 复用 称为 黑箱复用 ;

黑箱复用 看不到 , 如 A 类中包含 B 类 , A 看不到 B 的具体实现细节 ;





三、合成复用原则代码示例




1、继承复用代码示例


业务场景 : 向数据块中添加数据 ; 先获取数据库连接 , 然后向数据库中添加数据 ;

数据块链接类 :

package compositionaggregation;

/**
 * 数据块连接
 */
public class DBConnection {
    public String getConnection() {
        return "数据连接";
    }
}

增加数据类 :

package compositionaggregation;

/**
 * 创造产品
 */
public class ProductDao extends DBConnection {
    /**
     * 增加产品
     */
    public void addProduct() {
        // 先获取连接
        String conn = super.getConnection();
        System.out.println("使用 " + conn + " 增加产品");
    }
}

测试类 :

package compositionaggregation;

public class Main {
    public static void main(String[] args) {
        ProductDao productDao = new ProductDao();
        productDao.addProduct();
    }
}

执行结果 :


2、合成复用代码示例


数据库连接抽象类 :

package compositionaggregation;

/**
 * 数据块连接
 */
public abstract class DBConnection {
    public abstract String getConnection();
}

Oracle 数据库连接类 :

package compositionaggregation;

/**
 * Oracle 数据块连接
 */
public class OracleConnection extends DBConnection {
    @Override
    public String getConnection() {
        return "Oracle 数据库连接";
    }
}

MySQL 数据库连接类 :

package compositionaggregation;

/**
 * MySQL 数据块连接
 */
public class MySqlConnection extends DBConnection {
    @Override
    public String getConnection() {
        return "MySQL 数据库连接";
    }
}

插入数据类 : 通过组合复用 , 注入数据库连接类 ;

package compositionaggregation;

/**
 * 创造产品
 */
public class ProductDao {
    /**
     * 通过组合方式注入数据库连接
     */
    private DBConnection connection;

    public ProductDao(DBConnection connection) {
        this.connection = connection;
    }

    /**
     * 增加产品
     */
    public void addProduct() {
        // 先获取连接
        String conn = connection.getConnection();
        System.out.println("使用 " + conn + " 增加产品");
    }
}

测试类 :

package compositionaggregation;

public class Main {
    public static void main(String[] args) {
        ProductDao productDao = new ProductDao(new OracleConnection());
        productDao.addProduct();
    }
}

执行结果 :

以上是关于设计原则-合成复用原则的主要内容,如果未能解决你的问题,请参考以下文章

Java设计模式-合成复用原则

从零开始学习Java设计模式 | 软件设计原则篇:合成复用原则

从零开始学习Java设计模式 | 软件设计原则篇:合成复用原则

设计模式软件设计七大原则 ( 合成复用原则 | 代码示例 )

面向对象编程原则(08)——合成复用原则

面向对象编程原则(08)——合成复用原则