- 博客(77)
- 收藏
- 关注
原创 C++ STL(2)--算法(2)
保证对指定区域内数据完成分组的同时,不改变各组内元素的相对位置。用法和partition一样。根据用户自定义的筛选规则,重新排列指定区域内存储的数据,使其分为 2 组,第一组为符合。stable_sort函数是基于归并排序实现的,属于稳定排序。如果容器中存储的是自定义的对象,则该类必须提供移动构造函数和移动赋值运算符。筛选条件的数据,另一组为不符合筛选条件的数据。返回第二组的第一个元素。同时使所有比此元素小的元素在左侧,比它大的元素在右侧。sort函数是基于快速排序实现的,属于不稳定排序。
2024-01-06 20:38:12
494
原创 设计模式(4)--对象行为(11)--访问者
抽象访问者(Visitor)、具体访问者(Concrete Visitor)、抽象元素(Element)、6.4 增加新的ElementC,所有Visitor类和ObjectStructure都要修改(4.1)6.2 增加新的ConcreteVisitor3就可以定义一个新的操作(3.1)使你可以在不改变各元素的类的前提下定义于作用于这些元素的新操作。6.3 抽象Visitor里的接口集中了相关的操作(3.2)表示一个作用于某对象结构中的各元素的操作。3.2 集中相关的操作,而分离无关的操作。
2023-12-31 10:24:00
647
1
原创 设计模式(4)--类行为(10)--模板方法
6.2 ConcreteClass可以改变中间的两个步骤Operation1、Operation2。工厂方法是延迟到子类创建对象,模板方法是延迟到子类改变部分算法(行为)。6.1 AbstractClass::TemplateMethod定义了操作框架(步骤)。模板方法使子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。提取公共行为,父类调用子类操作。5.2 策略模式是改变整个算法,而模板方法是改变算法的一部分。定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
2023-12-31 09:32:39
618
原创 设计模式(4)--对象行为(9)--策略
抽象策略(Strategy)、具体策略(Concrete Strategy)、上下文环境(Context)定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。6.4 使用模板类时,具体策略可以不继承自抽象Strategy。3.2 一个替代继承的方法,算法独立于Context。6.3 相同的接口,但可得到不同的结果(3.4)本模式使得算法可独立于使用它的客户而变化。5.1 策略对象经常的轻量级的享元对象。3.4 提供了相同行为的不同实现。4.1 客户必须了解不同的策略。4.2 增加了对象的数目。
2023-12-30 14:45:04
739
原创 设计模式(4)--对象行为(8)--状态
上下文环境(Context)、抽象状态(State)、具体状态(Concrete State)3.1 将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。6.1 不同的ConcreteState,对应不同的处理方法(3.1)6.2 状态对象比多个一般变量更明确,更容易理解和管理(3.2)6.4 一个ConcreteState需要知道下一个状态是谁。允许一个对象在其内部状态改变时改变它的行为。6.3 代码里的状态对象是单例共享的(3.3)3.2 使得状态转换显式化。5.2 状态对象通常是单件。
2023-12-29 11:02:10
594
原创 设计模式(4)--对象行为(7)--观察者
抽象目标(Subject)、具体目标(Concrete Subject)、抽象观察者(Observer)、6.2 Subject::Notify里的循环就是广播,观察者自己决定是否处理某一通知(3.2)。5.1 ChangeManager可使用单例模式来保证它是唯一的并且是可全局访问的。当一个对象的状态改变时,所有依赖于它的对象都得到通知并被自动更新。当目标和观察者间的依赖关系特别复杂时,需要一个维护这些关系的对象,3.1 目标和观察者之间的耦合是抽象的。定义对象间的一种一对多的依赖关系,
2023-12-28 12:21:07
586
原创 设计模式(4)--对象行为(6)--备忘录
6.1 Originator通过Mememto来保存真实的内部状态,不保留历史状态(3.2)。6.2 Caretaker持有有历史状态的Mememto指针,但不关注其内部状态(3.1)。当生成备忘录必须拷贝并存储大量信息时,或非常频繁地创建备忘录和恢复原发器状态。在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。4.2 在一些语言中可能难于保证只有原发器可访问备忘录的状态。4.3 维护备忘录的潜在代价。5.1 命令模式可使用备忘录来为可撤销的操作维护状态。屏蔽了原发器的内部信息。
2023-12-27 08:56:55
464
原创 设计模式(4)--对象行为(5)--中介者
抽象中介者(Mediator)、具体中介者(Concrete Mediator)、抽象同事(Colleague)、5.1 Mediator的协议是多向的,提供了Colleague对象间的协作行为;而Façade的协议是单向的,只能Façade对子系统提出请求。6.2 将多对多的关系变成了一对多(一个中介对多个同事)的关系(3.3)。4.1 使控制集中化,可能使中介者自身称为一个难于维护的庞然大物。中介者使各对象不需要显式地相互引用,从而使其耦合松散,用一个中介对象来封装一系列的对象交互。
2023-12-26 20:20:51
568
1
原创 设计模式(4)--对象行为(4)--迭代器
抽象集合(Aggregate)、具体集合(Concrete Aggregate)、抽象迭代器(Iterator)、具体迭代器(Concrete Iterator)提供一种方法顺序访问一个聚合对象中的各个元素,而又不需暴露该对象的内部表示。6.2 使用方法一,可以得到多个迭代器,但用户需要负责删除迭代器指针(3.3);5.3 迭代器内部存储一个memento,用来捕获一个迭代的状态。6.1 可以很容易实现Iterator的子类以支持不同的遍历方式(3.1)3.1 支持以不同的方式遍历一个聚合。
2023-12-25 11:59:52
482
原创 设计模式(4)--类行为(3)--解释器
抽象表达式(AbstractExpression)、终结表达式(TerminalExpression)、非终结表达式(NonterminalExpression)、上下文(Context)给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语。6.1 可以很容易地改变解释器或增加新的终端解释器来实现新文法(3.1、3.2)。5.4 访问者可用来在一个类中维护抽象语法树中的各节点的行为。6.2 非终端解释器是组合模式,很容易实现新的“计算”(3.3)。3.2 易于实现文法。
2023-12-24 12:07:52
403
原创 设计模式(4)--对象行为(2)--命令
接收者(Receiver)、抽象命令(Command)、具体命令(Concrete Command)、请求者(Invoker)将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;6.2 增加新命令ConcreteCommand3,不需要修改其它类(3.4)。5.2 Memento模式可用来保持某个状态,命令用这一状态来撤消。6.1 请求者和接收者不直接打交道,而是通过命令对象(3.1)。3.1 将调用方(请求者)和操作方(接收者)解耦。3.4 容易增加新的命令,无需改变已有的类。
2023-12-23 11:17:46
482
原创 设计模式(4)--对象行为(1)--职责链
抽象处理者(Handler)、具体处理者(Concrete Handler)使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。3.1 降低耦合度。简化了对象的相互连接,仅需保持一个指向后继者的引用。6.1 每个具体处理者只需关注自己能处理的请求,其它请求丢给后继者(3.1)6.2 pHandler2只能处理一个请求,因为它在职责链的末端(4.1)4.1 不保证请求一定被处理(没有相应的处理者或使用不当)
2023-12-22 09:25:28
389
原创 设计模式(3)--对象结构(7)--代理
6.1 Proxy与RealSubject实现相同的接口,对客户隐藏了RealSubject,且可以访问权限控制。3.4 可以对用户隐藏copy-on-write的优化方式(大幅度地降低拷贝庞大实体时的开销)6.2 Proxy可以直接转发请求,也可以加一些内务处理或优化操作(3.3,3.4)。5.1 代理提供与实体相同的接口或子集接口,而适配器提供了一个不同的接口。5.2 代理控制对象的访问,而装饰器为对象添加一个或多个功能。为其它对象提供一种代理以控制对这个对象的访问。3.2 虚拟代理可以进行最优化。
2023-12-21 10:45:12
436
原创 设计模式(3)--对象结构(6)--享元
抽象享元(Flyweight)、具体享元(Concrete Flyweight)、具体不共享元(UnShared Concrete Flyweight)、享元工厂(Flyweight Factory)5.1 享元模式通常和组合模式结合,用共享叶节点的有向无环图实现一个逻辑上的层次结构。6.1 第二次使用SharedFlyweight时从map里取出,而不需要重新创建(3.1)5.2 通常,最好用享元实现State和Strategy对象。3.1 节省空间,共享越多,节省越大。4.1 增加了运行时开销。
2023-12-20 10:44:17
416
原创 设计模式(3)--对象结构(5)--外观
Façade的目的是对子系统对象的接口进行抽象,使更容易使用;5.2 Mediator的目的是对同事之间的任意通讯进行抽象,同事对象通过中介者与其他对象通信。为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得。3.1 对客户屏蔽了子系统组件,减少了客户处理的对象数目。子系统(Subsystem)、外观(Facade)3.2 实现了子系统与客户之间的松耦合关系。6.2 客户仍然可以直接使用子系统类(3.3)3.3 如果需要,仍然可以使用子系统类。这一子系统更加容易使用。
2023-12-19 10:31:48
428
原创 C++ STL(2)--算法(1)
可以传入普通函数或函数对象,作为自定义查找规则。//以函数对象的形式定义一个匹配规则public:if (it!cout << "最后一个被{2,4,6}整除的起始位置为:" << it - v1.begin() << ",*it = " << *it;return 0;
2023-12-18 15:18:30
529
原创 设计模式(3)--对象结构(4)--装饰
一个被装饰了的组件与这个组件是有差别的,使用装饰时不能依赖对象标识。5.2 可以将装饰视为一个退化的,仅有一个组件的组合,但它的目的不在于对象聚集。3.2 避免在层次结构高层的类有太多的特征。5.1 装饰仅改变对象的职责而不改变接口,而适配器给对象一个全新的接口。5.3 装饰可以改变对象的外表,而策略模式可以改变对象的内核。6.2 不同的装饰器可以添加不同的功能,也可以叠加给被装饰者(3.2)6.1 装饰不是单纯的继承,它还持有被装饰者的指针,更灵活(3.1)动态地给一个对象添加一些额外的功能。
2023-12-18 10:36:29
495
原创 设计模式(3)--对象结构(3)--组合
Composite使得用户对单个对象和组合对象的使用具有一致性。抽象组件(Component)、组合式节点(Composite)、叶节点(Leaf)6.2 Leaf也是一种基本对象,只需要关注Component接口(3.2)。6.1 组合Composite是一种基本对象Component(3.1)。6.2 继承Component接口,就可以增加新类型的组件(3.3)。客户代码中,用到基本对象的地方都可以使用组合对象。3.1 定义了包含基本对象和组合对象的类层次结构。3.4 使设计变得更加一般化。
2023-12-17 16:02:05
389
原创 设计模式(3)--对象结构(2)--桥接
抽象(Abstraction)、细化抽象(Refined Abstraction)、抽象实现者(Implementor)、具体实现者(Concrete Implementor)6.1 接口Abstraction和实现Implementor分离,接口类维护一个实现类的指针(3.1)6.2 可以单独对Abstraction或Implementor扩充(生成新的子类)(3.2)5.2 适配器模式用来帮助无关的类协同工作,通常在系统完成后(类已经设计好)才使用,而桥接模式在系统开始时(设计类之前)就被使用。
2023-12-16 11:09:13
432
原创 设计模式(3)--对象结构(1)--适配器
6.2 对象适配器ObjectAdapter不需要修改代码,就可以对Adaptee的子类同样适配(3.2.a)a. Adapter可以重定义Adaptee的部分行为,因为Adapter是它的一个子类。5.1 Adapter是改变一个已有对象的接口,而Bridge是将接口和实现分离。a. 允许一个Adapter与多个Adaptee(其本身及它的所有子类)。a. 一个Adapter只能对应一个Adaptee(不能适配其子类)。5.3 Proxy在不改变它的接口的条件下,为另一个对象定义了一个代理。
2023-12-15 09:34:39
483
1
原创 C++ STL(1)--概述
六大组件之间的关系,容器通过分配器取得数据存储空间,算法通过迭代器访问容器中的内容,仿函数可以协助算法完成不同的策略的变化,适配器可以修饰容器(使其表现出另一种行为)。可以自定义仿函数,也可以使用STL内建的仿函数(必须包含<functional>头文件)。内部表示的情况下,按照一定顺序(由iterator提供的方法)访问聚合对象中的各个元素。仿函数适配器是一种特殊的函数对象,它可以将一个仿函数转换为另一个仿函数,或者将一。1.2 它不是面向对象的,是基于模板(template)的。适配器就是接口模板。
2023-12-14 10:39:10
894
原创 设计模式(2)--对象创建(5)--单件
6.2 将构造函数私有化,只能通过Instance函数访问对象。保证一个类仅有一个实例,并提供一个访问它的全局访问点。很多模式都可以用单例实现,如抽象工厂、生成器、原型。3.3 允许对操作和表示精化(可以有子类)3.2 缩小名空间(对全局变量的改进)6.1 注意此代码未考虑线程安全问题。3.1 对唯一实例的受控访问。单件(Singleton)3.4 允许可变数目的实例。3.5 比类操作更灵活。
2023-12-14 09:12:30
473
原创 设计模式(2)--对象创建(4)--原型
5.2 大量使用Composite和Decorator模式的设计通常可以从原型模式处获益。抽象原型(Prototype)、具体原型(Concrete Prototype)抽象工厂可以存储一个被克隆的原型的集合,并且返回产品对象。5.1 原型和抽象工厂在某种方面是相互竞争的,但它们也可以一起使用。这可能很困难,当内部有不支持拷贝或循环引用的对象时。用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。3.3 可以极大地减少系统所需要的类的数目。3.5 可以减少子类的构造。3.6 用类动态配置应用。
2023-12-13 15:47:10
476
原创 设计模式(2)--对象创建(3)--工厂方法
5.3 原型不需要创建Creator子类,但需要Creator初始化产品对象,工厂方法则不需要。3.2 给子类一个钩子(hook)以提供对象的扩展版本(父类有个缺省版本)6.1 可以直接操作Product的接口(3.1),也可以通过Creator操作。4.1 可能为了创建一个特定的具体产品对象,不得不创建一个具体构造者。定义一个用于创建对象的接口,让子类决定实例化哪一个类。抽象产品、具体产品、抽象构造者、具体构造者。3.3 可以连接平行的类层次(职责委托)工厂方法使一个类的实例化延迟到其子类。
2023-12-13 09:40:18
590
原创 设计模式(2)--对象创建(2)--生成器
指挥(Director)、抽象生成器(Builder)、具体生成器(Concrete Builder)、产品(Product)5.1 Builder着重于一步步构造一个复杂对象,而抽象工厂着重于多个系列的产品对象。将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。6.2 可以创建不同的Director来控制所需零件来组成不同产品(3.2)。6.3 Director的Construct函数可以控制构造过程(3.3)。3.1 可以改变一个产品的内部表示(通过定义新的生成器)。
2023-12-13 09:36:28
449
原创 设计模式(2)--对象创建(1)--抽象工厂
抽象产品(Product)、具体产品(Concrete Product)、抽象工厂(Abstract Factory)、具体工厂(Concrete Factory)。5.1 抽象工厂类通常用工厂方法(Factory Method)实现,也可用原型(Prototype)实现。一个更灵活但不太安全的方法是给创建对象的操作增加一个参数,该参数指定对象的种类。提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。5.2 一个具体的工厂通常是一个单件(Singleton)。3.1 分离了具体的类。
2023-12-12 15:31:36
542
原创 设计模式(1)--面向对象的设计原则
本质是指软件功能有变化时(业务逻辑变化),不修改已有的代码,而是应该通过扩展来实现变化。子类继承父类时,必须是is-a的关系,子类可以扩展父类的功能,但不能改变父类原有的功能。一个类对于其他的类知道的越少越好,就是说一个对象只和必须的有限对象打交道。也就是细化接口(单一职责),使用多个专门的接口,而不使用单一的总接口。3.1 高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。这个原则的意思是任何基类对象出现的地方,都可以用子类对象替换。所有的类/对象/方法都应该有单一的职责,也就是只做一件事。
2023-12-12 15:22:54
470
原创 《Effective C++》知识点(9)--杂项讨论
54.3 TR1自身只是一份规范,为获得TR1提供的好处,你需要取得实现代码。Boost程序库包含。53.1 严肃对待编译器发出的警告信息。努力在你的编译器的最高警告级别下争取"无任何警告"。53.2 不要过度依赖编译器的报警能力,因为不同的编译器对待事情的态度并不相同。在忽略某个警告之前,请确保你了解它意图说出的精确意义。到另一个编译器上,你原本依赖的警告信息有可能消失。是个template,以其目标函数的签名(指明参数和返回值类型)为参数。54.1 C++98标准库。55.2 Boost组件。
2023-11-14 14:58:19
84
原创 《Effective C++》知识点(8)--定制new和delete
52.2 当你声明placement new和placement delete,请确保没有掩盖它们的正常版本(条款33)。d. 抛出bad_alloc(或派生自bad_alloc)的异常(不被operator new捕捉)。b. 类的专属版本应该能处理"与正确大小不一致的(错误)"申请(交给标准operator delete)。c. 类的专属版本应该能处理"与正确大小不一致的(错误)"申请(交给标准operator new)。期多态(静态多态),其中基类A用来定义(暴露)接口,派生类X用来实现这些接口。
2023-11-13 09:12:17
78
原创 《Effective C++》知识点(7)--模板与范型编程
46.1 在template实参推导过程中从不将隐式类型转换函数纳入考虑。46.2 template class内的friend声明式可以指涉某个特定函数。使用friend是目的是支持"所有参数的隐式类型转换"。46.3 为了让类型转换可能发生于所有实参身上,我们需要一个非成员函数;为了令这个函数被自动具现化,我们需要将它声明在class内部;而在class内部声明非成员函数的唯一办法就是令它为friend。这里使用friend与它的传统用途"访问class内非public成分"没有关系。
2023-11-10 10:53:17
83
原创 《Effective C++》知识点(6)--继承与面向对象设计
任何情况下继承类都不该重新定义一个继承而来的基类non-virtual函数。如果需要重新定义,那说明这个函数其实应该是virtual函数。37.1 可以重定义继承而来的带有缺省参数值的virtual函数实现,但不能重定义它的缺省参数值。因为virtual函数是动态绑定,而缺省参数值却是静态绑定。37.2 为什么缺省参数值是静态绑定?为了运行效率。如果缺省参数值是动态绑定,编译器就必须有某种办法在运行期为虚函数决定适当的参数缺省值。这比目前实行的"在编译期决定"的机制更慢而且更复杂。为了。
2023-11-04 17:32:57
134
原创 《Effective C++》知识点(5)--实现
26.1 "尽可能延后"的真正意义是:你不只应该延后变量的定义,直到非得使用该变量的前一刻 为止,甚至应该尝试延后这份定义直到能够给它初值实参为止。a. 提高了程序效率。不仅避免了构造和析构非必要对象,还可以避免无意义的default构造。b. 提高了代码清晰度。以"具有明显意义之初值"将变量初始化,还可以附带说明变量的目 的。26.2 对于循环,对象是应该定义在循环外还是循环内?
2023-10-31 17:09:40
72
原创 《Effective C++》知识点(4)--设计与声明
25.1 当std::swap对你的类型效率不高时,提供一个public的swap成员函数,并确保这个函数不抛出异常。18.3 "阻止误用"的办法包括建立新类型、限制类型上的操作(什么事可做,什么事不能做)、限制对象值、以及消除客户的资源管理责任。18.2 "促进正确使用"的办法包括接口的一致性,以及与内置类型的行为兼容(尽量令你的types的行为与内置types一致)。21.1 当你必须在"返回一个引用"和"返回一个对象"之间选择时,你的工作就是挑出行为正确的那个,剩下的交给编译器。
2023-10-28 20:55:21
145
原创 《Effective C++》知识点(3)--资源管理
16.2 如果在new表达式中没有使用[],一定不要在相应的delete中使用[],否则可能删除不属于它的内存,造成不可预测的结果。std::tr1::shared_ptr应优先选择,它是引用计数智能指针(RCSP),可以多个指向同一对。16.1 如果在new表达式中使用[],必须在相应的delete表达式中也使用[],否则内存泄漏。d. 转变底层资源的拥有权,确保只有一个RAII对象指向资源,如auto_ptr。缺点是无法打破环状引用(如两个没用的对象彼此互指),这点需要注意。
2023-10-25 10:03:24
116
原创 《Effective C++》知识点(2)--构造/析构/赋值运算
9.1 构造函数的调用顺序是,先调基类构造,再调继承类构造。在基类构造函数中调用虚函数,此时继承类尚未构造,其成员变量也没有初始化,所以此时对象还是基类对象,基类构造函数里调用的其它函数,只能是基类定义的函数。基类析构函数里调用的其它函数,只能是基类定义的函数。5.3 编译器拒绝生成operator=函数的情况:一是有引用成员变量,二是有const成员变量,三是基类的operator=函数是私有的。如果这个类有基类,且基类析构函数是virtual的,这时它的析构函数才是virtual的。
2023-10-23 16:39:43
81
原创 《Effective C++》知识点(1)--让自己习惯C++
但是C++保证,函数内的local static对象会在"该对象被调用期间"首次遇上该对象定义式时被初始化。所以请优先使用局部静态对象函数,而不是全局静态对象,可以避免依赖的静态对象未被初始化的情况。3.4 当const和non-const成员函数有着实质等价的实现时,另non-const版本调用const版本可以避免代码重复。先用static_cast将*this转为const对象调用const成员函数,再用const_cast移除调用返回的const修饰。处理的,编译器不知道它的存在。
2023-10-21 16:39:03
115
原创 排序算法(Java实现)
冒泡排序属于交换排序。效率较低,适用小规模数据集。原理:循环遍历要排序的元素,依次比较两个相邻的元素,每次循环都找到一个最大(或最小)的数放到最后(或最前)。没有相邻元素需要交换时,说明已经排序完成。它是稳定排序 (即相等的两个元素,在排序后相对位置不会发生变化)。改进算法1,记录本此循环有无数据交换,若无则表示数据已经有序,跳出循环。改进算法2,改进算法1加上记录本次循环比较交换的最后位置,后面的元素是有序的,下次循环无需再比较最后位置元素之后的数据。
2023-10-17 11:40:04
419
1
原创 《Effective Java》知识点(11)--序列化
选择错误的序列化形式对于一个类的复杂性和性能都会有永久的负面影响。87.1 如果事先没有认真考虑默认的序列化形式是否合适,则不要贸然接受。如果一个对象的物理表示法等同于它的逻辑内容,可能适合使用默认的序列化形式。即使确定了默认的序列化形式是合适的,通常还必须提供一个readObject方法以保证约束关系和安全性。87.2 当一个对象的物理表示法与它的逻辑数据内容有实质性的区别时,使用默认的序列化形式会有以下4个缺点:a. 它使这个类的导出API永远地束缚在该类的内部表示法上。
2023-10-12 10:06:33
142
原创 《Effective Java》知识点(10)--并发
在一个被同步的区域内部,不要调用设计成要被覆盖的方法,或者是由客户端以函数对象的形式提供的方法。同步不仅可以阻止一个线程看到对象处于不一致的状态中,它还可以保证进入同步方法或者同步代码块的每个线程,都能看到由同一个锁保护的之前所有的修改效果。类的实例是可变的,但有足够的内部同步,所以不需要外部同步,如AtomicLong和ConcurrentHashMap。不要企图通过调用Thread.yield来“修正”程序,因为这样的程序不可移植,同一个yield调用在不同的JVM实现上是不一样的。
2023-10-09 10:36:01
60
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人