文章目录
- 1. 面向对象的特点是什么?
- 2. 让面向对象保持结构良好的秘诀是什么?
- 3. 六大设计原则是什么?
- 4. 什么是里氏替换原则?
- 5. 工厂模式是用于达到什么目的的设计模式?
- 6. 工厂模式有哪三种?
- 7. 工厂方法模式解决了简单工厂模式的哪两个弊端?
- 8. 抽象工厂模式是什么样的?
- 9. 抽象工厂模式很好的发挥了哪些原则?
- 10. 抽象工厂模式的缺点是什么?
- 11. 抽象工厂模式适用于和不适用于哪些情况?
- 12. 什么时候可以使用单例模式?
- 13. 单例模式的优点是什么?
- 14. 单例模式有哪两种实现方式?请分别简单解释。
- 15. 饿汉式的弊端是什么?
- 16. 建造者模式用于什么时候?
- 17. 建造者模式是什么意思?
- 18. 现在建造者模式主要用来做什么?
- 19. 使用建造者模式的好处是什么?
- 20. 原型模式是什么?
代码仓库
1. 面向对象的特点是什么?
可维护、可复用、可扩展、灵活性好。
2. 让面向对象保持结构良好的秘诀是什么?
让面向对象保持结构良好的秘诀就是设计模式,面向对象结合设计模式,才能真正体会到程序变得可维护、可复用、可扩展、灵活性好。
3. 六大设计原则是什么?
开闭原则、单一职责原则、里氏替换原则、依赖倒置原则、迪米特原则、接口隔离原则。
- 单一职责原则(SRP)
一个类/模块只负责一项职责(只有一种导致它变化的原因)。好处:降低耦合、提升可维护性。 - 开闭原则(OCP)
对扩展开放、对修改关闭。通过抽象与多态,让新增功能以“加类/加实现”为主,尽量不改已有代码。 - 里氏替换原则(LSP)
子类必须能替换父类而不破坏程序正确性。不要收紧父类的前置条件、不要放宽后置条件;遵守行为契约。 - 依赖倒置原则(DIP)
高层模块不依赖低层模块,二者都依赖抽象;具体实现依赖抽象而不是相反。常用依赖注入/接口注入落地。 - 接口隔离原则(ISP)
使用多个小而专用的接口,而不是一个大而全的“胖接口”。客户端不应被迫依赖它不需要的方法。 - 迪米特法则(LoD,最少知道原则)
减少不必要的耦合,只与“直接的朋友”交互, 避免“火车点”式调用(a.b().c().d()),隐藏内部细节。
4. 什么是里氏替换原则?
子类应该可以完全替换父类。也就是说在使用继承时,只扩展新功能,而不要破坏父类原有的功能。
5. 工厂模式是用于达到什么目的的设计模式?
封装对象。
6. 工厂模式有哪三种?
简单工厂模式、工厂方法模式、抽象工厂模式。
7. 工厂方法模式解决了简单工厂模式的哪两个弊端?
当生产的产品种类越来越多时,工厂类不会变成超级类。工厂类会越来越多,保持灵活。不会越来越大、变得臃肿。如果苹果的生产过程需要修改时,只需修改苹果工厂。梨子的生产过程需要修改时,只需修改梨子工厂。符合单一职责原则。
当需要生产新的产品时,无需更改既有的工厂,只需要添加新的工厂即可。保持了面向对象的可扩展性,符合开闭原则。
8. 抽象工厂模式是什么样的?
在创建时指定了具体的工厂类后,在使用时就无需再关心是哪个工厂类,只需要将此工厂当作抽象的 IFactory 接口使用即可。抽象工厂内部常用若干工厂方法来实现
工厂方法:一个工厂方法 → 造一种产品的多实现。
抽象工厂:一个工厂接口里含多种产品的工厂方法 → 造一整套配套产品。
9. 抽象工厂模式很好的发挥了哪些原则?
开闭原则、依赖倒置原则。
依赖倒置原则(DIP)要求的是:高层业务代码只依赖抽象(AbstractFactory、AbstractBall、AbstractShirt),不直接依赖具体类;
10. 抽象工厂模式的缺点是什么?
缺点是抽象工厂模式太重了,抽象工厂的“痛点”主要在新增“产品类型”(即给 IFactory 增加新的 createX())会牵一发动全身,会影响到所有的具体工厂类,必须修改所有具体工厂去实现它,否则编译不过。使用抽象工厂模式,替换具体工厂时只需更改一行代码,但要新增抽象方法则需要修改所有的具体工厂类。
但这不是模式“设计失误”,而是它的适用前提:类型稳定、族可变。
11. 抽象工厂模式适用于和不适用于哪些情况?
适用于增加同类工厂这样的横向扩展需求,不适合新增功能这样的纵向扩展。
12. 什么时候可以使用单例模式?
某个对象全局只需要一个实例时即可。
13. 单例模式的优点是什么?
• 它能够避免对象重复创建,节约空间并提升效率
• 避免由于操作不同实例导致的逻辑错误
14. 单例模式有哪两种实现方式?请分别简单解释。
饿汉式和懒汉式。饿汉式指变量在声明时便初始化。懒汉式指先声明一个空变量,需要用时才初始化。
15. 饿汉式的弊端是什么?
即使这个单例不需要使用,它也会在类加载之后立即创建出来,占用一块内存,并增加类初始化时间。
16. 建造者模式用于什么时候?
创建过程稳定,但配置多变的对象。
17. 建造者模式是什么意思?
将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
建造者(Builder)模式就是:把“复杂对象的构建过程”从“对象本身”里独立出来,用一步步配置 → 最后 build() 产出的方式创建对象。这样同样的一套构建步骤也能产出不同表现/配置的对象;调用端写法像“链式命名参数”,清晰、可校验。
18. 现在建造者模式主要用来做什么?
通过链式调用生成不同的配置。
可选参数很多:避免“伸缩构造函数地狱”,用流式 API 清晰表达
HttpRequest::Builder{}.method(“GET”).url(u).header(k,v).timeout(2000).build();
#include <string>
#include <vector>
#include <utility>
#include <stdexcept>
class HttpRequest {
public:
class Builder {
public:
Builder& method(std::string m) { method_ = std::move(m); return *this; }
Builder& url(std::string u) { url_ = std::move(u); return *this; }
Builder& timeout_ms(int t) { timeout_ms_ = t; return *this; }
Builder& follow_redirects(bool f) { follow_redirects_ = f; return *this; }
Builder& header(std::string k, std::string v) {
headers_.emplace_back(std::move(k), std::move(v)); return *this;
}
Builder& body(std::string b) { body_ = std::move(b); return *this; }
HttpRequest build() {
// 集中校验 + 填默认值
if (method_.empty() || url_.empty())
throw std::logic_error("method and url are required");
if (method_ == "GET" && !body_.empty())
throw std::logic_error("GET must not have a body");
if (timeout_ms_ <= 0) timeout_ms_ = 3000;
return HttpRequest(method_, url_, headers_, body_, timeout_ms_, follow_redirects_);
}
// 防止共享中间状态导致错用
Builder(const Builder&) = delete;
Builder& operator=(const Builder&) = delete;
private:
std::string method_, url_, body_;
std::vector<std::pair<std::string, std::string>> headers_;
int timeout_ms_ = 0;
bool follow_redirects_ = false;
};
private:
HttpRequest(std::string m, std::string u,
std::vector<std::pair<std::string,std::string>> h,
std::string b, int t, bool f)
: method_(std::move(m)), url_(std::move(u)),
headers_(std::move(h)), body_(std::move(b)),
timeout_ms_(t), follow_redirects_(f) {}
std::string method_, url_, body_;
std::vector<std::pair<std::string,std::string>> headers_;
int timeout_ms_;
bool follow_redirects_;
};
// 调用处:链式“命名参数”,一眼能看懂含义
auto req1 = HttpRequest::Builder{}
.method("GET").url("/api/ping").timeout_ms(2000).build();
auto req2 = HttpRequest::Builder{}
.method("POST").url("/login")
.header("Accept","application/json")
.body(R"({"u":"alice","p":"secret"})")
.follow_redirects(true)
.timeout_ms(5000)
.build();
伸缩构造函数地狱
19. 使用建造者模式的好处是什么?
不用担心忘了指定某个配置,保证了构建过程是稳定的。
20. 原型模式是什么?
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
之后我会持续更新,如果喜欢我的文章,请记得一键三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持!