论接口的封装能力

news/2025/2/19 17:52:22/

刚入职行业不到一年的菜鸟的心得体会,真实感受,不喜勿喷。

        为什么想到封装呢?还不是因为踩过坑,最近越来越感觉,直接用一些开源库很不方便,而且用起来总是忘塞。

        1.在工程开发过程中,我们不可避免的会用到其他人封住好的库。当然,作为程序员的基础素养之一,我们也得会封住一些好用的库,不仅仅是为了更好的迭代工程,更为了更好的使用一些开源库。

        2.说到开源库,最近蛮烦恼塞。因为刚入职从事程序员行业,这段时间一直在接触开源库还有一些开源框架。(我感觉看多了,开始习惯看源码了,之前都直接看博客。额,看不可的效果不可描述,总感觉很多时候看不明白,所以塞,不如看源码里的例子,遇到具体的点没明白的再去百度或者请教前辈。)

        3.最最重要的一点就是很多开源库为了支持更多的功能,在使用过程中会比较繁琐,并且很多时候我们只想使用一部分功能,通常我们会选择提前做一层封装。(自己封装的塞,肯定用得爽,虽然封住过程有点痛苦塞,长痛不如短痛塞)

封住一定要很规范 

        个人觉得如果业务很简单,其实好用就行了,封装最初的目的也是为了好用。如果比较复杂的设计,比如好几个库杂糅在一起,而且之后会有功能扩展的需求,那么这个时候就得先考虑下,如何设计会比较好了。

        对于第一种情况,就不过多的描述了,很简单的。通常可以用C方式,也可以采用C++类的方式(看情况决定,为了自己方便)。

详细说下第二种情况 

接口设计注意事项:

1.避免过度封装,过度封装会导致调bug很难理清楚逻辑,而且很不好维护

2.接口名称,通常使用驼峰规则就行,做到见名思意

3.参数尽量提炼,不要搞一堆没必要的参数,用起来很麻烦。无非必要,就不要

4.注释清晰,明了。不写注释是王八

接口设计的最佳效果

1.隔离用户操作与底层逻辑

(说人话,无非就是我给你这个接口就可以让你实现这个功能,不需要你去了解里面怎么玩的,想那么多干嘛,那是我封住接口的人需要考虑的塞)

 接口封装的两种方法

1.PIMP(Pointer to Implementation)在接口类成员中包含一个指向实现类的指针,这样就可以最大限度的做到接口和实现进行分离的原则。

说白了,就是A实现了某种方法(类A不对外使用),而在A-inerface中声明一个A *pA,并且这套接口的方法内部就是调用了A的方法,有时候可能会做一些扩展,比如一个基础事件的集合,也就是有很多这样的事件

示例:

class A_interface

{

public:

        A_interface& operator+(const A_interface& com );
        A_interface& operator-(const A_interface& com );
        A_interface& operator*(const A_interface& com );
        A_interface& operator/(const A_interface& com );

private:

        A *p_A;

}

class A{
public:
        A& operator+(const A& com );
        A& operator-(const A& com );
        A& operator*(const A& com );

        A& operator/(const A& com );

private:
        double real_;
        double imaginary_;
};

===> 不可多说,这个方法反正我基本不用塞,自己体会塞

2.Object-Interface方法,采用c++继承多态,实现类继承接口类,功能接口定义成虚函数。

这个纯虚函数给你朋友用,其他部分搞成.so或者.dll (.lib\.a)

如果不满足塞,再来个管理类。说白了就一个工厂类塞,如果你觉得好玩,可以搞个反射塞。

//纯虚函数,接口成员函数
class Complex{
public:
    static std::unique_ptr<Complex> Create();    // 用来做工厂方法     
    virtual Complex& operator+(const Complex& com ) = 0;
    virtual Complex& operator-(const Complex& com )  = 0;
    virtual Complex& operator*(const Complex& com )  = 0;
    virtual Complex& operator/(const Complex& com )  = 0;
};

//Complex类功能的内部实现类
class ComplexImpl : public Complex{
public:
    virtual Complex& operator+(const Complex& com ) override;
    virtual Complex& operator-(const Complex& com ) override;
    virtual Complex& operator*(const Complex& com ) override;
    virtual Complex& operator/(const Complex& com ) override;
private:
    double real_;
    double imaginary_;
}

>>>将要暴露出去的接口都设置为纯虚函数,然后通过工厂模式Create获取不同基类的指针
std::unique_ptr<Complex> Complex::Create()
{
    return std::make_unique<ComplexImpl>();
}
>>>如此,我们完成将Complex类的实现细节全部封装隐藏起来了
>>>如果对于用户来说,是有必要获取实体的数据部分时,只需要添加响应的set和get方法

Object_interface抽象基类示例代码:
1.首先,声明一个接口 ---> 一般设置为纯虚函数

// circle.h
// 圆的接口类
class Circle {
public:
   virtual ~Circle() {};
   virtual double area() = 0;     // 接口方法:面积
};

2.通过继承的方式实现这个接口

// circle_impl.h
#include "circle.h"
 
// 圆的具体实现类
class CircleImpl : public Circle { 
private:
    double radius;
public:
    CircleImpl(double radius);
    double area() override;
};

// circle_impl.cpp
#include <cmath>
#include "circle_impl.h"
 
inline double pi() {
    return std::atan(1) * 4;
};
 
CircleImpl::CircleImpl(double _radius) : radius(_radius) {
};
 
double CircleImpl::area() {
    return pi() * radius * radius;
};

3.最后,通过管理类创建接口派生类的实例,或者销毁接口派生类的实例
// circle_manager.h
#include "circle.h"
 
// 圆的创建工厂类
class CircleManager {
public:
    static Circle* create(double radius);     // 创建circle实例
    static void destroy(Circle* circlePtr);   // 销毁circle实例
};

// circle_manager.cpp
#include "circle_manager.h"
#include "circle_impl.h"
 
Circle* CircleManager::create(double radius) {
    Circle* circlePtr = new CircleImpl(radius);
 
    return circlePtr;
};
 
void CircleManager::destroy(Circle* circlePtr) {
    delete circlePtr;
}; 

// 使用示例
// main.cpp
#include <iostream>
#include "circle_manager.h"
#include "circle.h"
 
int main() 
{
    Circle* circlePtr = CircleManager::create(3);
    cout << circlePtr->area() <<endl;
    CircleManager::destroy(circlePtr);
    
    system("pause");
 
    return 0;
}
 


http://www.ppmy.cn/news/56535.html

相关文章

定位的特殊应用

注意&#xff1a;发生固定定位&#xff0c;绝对定位后&#xff0c;元素都变成了定位元素&#xff0c;默认高宽被内容撑开&#xff0c;则可以设置宽高&#xff1b;以下只针对绝对定位和固定定位的元素&#xff0c;不包括相对定位元素。 1.定位元素块的宽充满包含块 前提&#x…

C#基础 (类型转换_隐式转换)

什么是类型转换 类型转换就是不同变量类型之间的相互转换 隐式转换的基本规则——>不同类型之间自动转换 大范围装小范围 相同大类型之间的转换 有符号 long——>int——>short——>sbyte 可以用大范围装小范围的类型&#xff08;隐式转换&#xff09; 不能够用小范…

PostgreSQL16中pg_dump的LZ4和ZSTD压缩

PostgreSQL16中pg_dump的LZ4和ZSTD压缩 pg_dump压缩lz4和zstd LZ4和ZSTD压缩算法合入了PG16。LZ4补丁的作者是Georgios Kokolatos。由Tomas Vondra提交。由Michael Paquier、Rachel Heaton、Justin Pryzby、Shi Yu 和 Tomas Vondra 审阅。提交消息是&#xff1a; Expand pg_dum…

SpringBoot高频面试题

Springboot的优点 内置servlet容器&#xff0c;不需要在服务器部署 tomcat。只需要将项目打成 jar 包&#xff0c;使用 java -jar xxx.jar一键式启动项目SpringBoot提供了starter&#xff0c;把常用库聚合在一起&#xff0c;简化复杂的环境配置&#xff0c;快速搭建spring应用…

传统机器学习(六)集成算法(1)—随机森林算法及案例详解

传统机器学习(六)集成算法(1)—随机森林算法及案例详解 1、概述 集成学习&#xff08;Ensemble Learning&#xff09;就是通过某种策略将多个模型集成起来&#xff0c;通过群体决策来提高决策准确率。 集成学习首要的问题是选择什么样的学习器以及如何集成多个基学习器&…

【数据库】JDBC编程

前言 小亭子正在努力的学习编程&#xff0c;接下来将开启javaEE的学习~~ 分享的文章都是学习的笔记和感悟&#xff0c;如有不妥之处希望大佬们批评指正~~ 同时如果本文对你有帮助的话&#xff0c;烦请点赞关注支持一波, 感激不尽~~ 目录 前言 什么是JDBC&#xff1f; JDBC工…

KubeSphere 社区双周报 | 杭州站 Meetup 议题征集中 | 2023.04.14-04.27

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者&#xff0c;并对近期重要的 PR 进行解析&#xff0c;同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为&#xff1a;2023.04.14-2023.…

稀疏矩阵存储格式总结

稀疏矩阵是指矩阵中的元素大部分是0的矩阵&#xff0c;实际问题中大规模矩阵基本上都是稀疏矩阵&#xff0c;很多稀疏度在90%甚至99%以上,大规模的稀疏造成了大量无效数据的计算和存储资源占用&#xff0c;也无法有效的载入有限内存计算。因此我们需要有高效的稀疏矩阵存储格式…