设计模式学习笔记
SOLID 设计原则
单一职责原则(SRP)
单一职责原则是指每个类设计的时候职责尽可能单一,因此只有该职责需要变化时才需要修改这个类。尽可能少的修改代码。
开闭原则
开闭原则就是对扩展开放,对修改关闭。已经写好的类,当需要修改或者增加新的扩展功能时,不需要修改已经写好测试过的代码。
里氏替换原则
某个接口以基类对象做为参数,那么它因该同等地接受子类对象做为参数,并且程序不会产生任何异常。
接口隔离原则
接口隔离原则地基本思想是将复杂的接口分离为多个单独的接口,以避免强制实现者必须实现某些他们实际上并不需要的接口。
依赖倒转原则
高层模块不应该依赖低层模块,他们都应该依赖抽象接口。抽象接口不应该依赖细节,细节应该依赖抽象接口。
为为
创建型模式(5种)
- 构建器
- 单例
- 工厂方法
- 抽象工厂
- 原型
构造器模式
传统构造方法
构造器模式主要是用于复杂对象的构造,复杂对象的内部具有多个成员变量,构造的时候往往采用具有多个形参的构造函数,多个形参具有多种组合,导致构造函数要写多个;或者在构造后调用set函数给成员变量赋值。
#include "pch.h"
#include <iostream>
#include <string>
using namespace std;
class Student
{
public:
Student();
Student(int id)
{
this->id = id;
}
Student(int id, int score, const string & name)
{
this->id = id;
this->score = score;
this->name = name;
}
Student(int id, int age)
{
this->id = id;
this->age = age;
}
void setId(int id)
{
this->id = id;
}
void setScore(int score)
{
this->score = score;
}
void setName(const string & name)
{
this->name = name;
}
void setAdress(const string & adress)
{
this->adress = adress;
}
~Student();
private:
int id;
int score;
string name;
string adress;
int age;
};
Student::Student()
{
}
Student::~Student()
{
}
int main()
{
Student student1(0, 100, "xiaoming");
Student student2;
student2.setName("xiaoli");
student2.setId(1);
student2.setScore(99);
student2.setAdress("lock street");
std::cout << "Hello World!\n";
}
使用上述方法构造对象的时候显得很麻烦,要么需要写多个类型的构造函数,要么需要多次调用set。使用构造器就可以使得构造变得更加灵活简洁。
构造器
jave实现
Java典型的Builder模式需要的类
- 需要构造的实体类
- 实体类中需要一个具体的构造类
- 构造类中需要聚合一个需要构造的实体类对象
- 构造类中需要写各种构造该实体类中不同属性的方法
- 构造类中还需要一个构造结束的方法build(),返回的对象是内聚的实体类
/**
* 典型的java中builder模式
* @Author ChenJiahao(程序员五条)
* @Date 2021/9/22 22:43
*/
public class Person {
int id;
String name;
int age;
double weight;
int score;
Location loc;
private Person(){}
public static class PersonBuilder{
Person p = new Person();
public PersonBuilder basicInfo(int id,String name,int age){
p.id = id;
p.name = name;
p.age = age;
return this;
}
public PersonBuilder weight(double weight){
p.weight = weight;
return this;
}
public PersonBuilder score(int score){
p.score = score;
return this;
}
public PersonBuilder loc(String street,String roomNo){
p.loc = new Location(street,roomNo);
return this;
}
public Person build(){
return p;
}
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", weight=" + weight +
", score=" + score +
", loc=" + loc +
'}';
}
}
/**
* Person中引用的属性
* @Author ChenJiahao(程序员五条)
* @Date 2021/9/22 22:39
*/
public class Location {
String street;
String roomNo;
public Location(String street, String roomNo) {
this.street = street;
this.roomNo = roomNo;
}
}
/**
* @Author ChenJiahao(程序员五条)
* @Date 2021/9/22 22:55
*/
public class Test {
public static void main(String[] args) {
// 下面.后面的不想要的可以注掉
Person p = new Person.PersonBuilder()
.basicInfo(1,"zhangsan",18)
// .score(20)
.weight(200)
// .loc("bj","23")
.build();
System.out.println(p);
}
}
C++语言实现
#include "pch.h"
#include <iostream>
#include <string>
using namespace std;
class StudentBuilder;
class Student
{
friend class StudentBuilder;
public:
static unique_ptr<StudentBuilder> build()
{
return make_unique<StudentBuilder>();
}
void PrintInfo()
{
cout << "id:" << id << endl << "score:" << score << endl << "name:" << name << endl << "adress:"
<< adress << endl << "age:" << age << endl;
}
~Student() {};
private:
int id;
int score;
string name;
string adress;
int age;
Student() {};
};
class StudentBuilder
{
public:
StudentBuilder() {};
~StudentBuilder() {};
StudentBuilder& id(int id)
{
student.id = id;
return *this;
}
StudentBuilder& score(int score)
{
student.score = score;
return *this;
}
StudentBuilder& name(const string & name)
{
student.name = name;
return *this;
}
StudentBuilder& adress(const string & adress)
{
student.adress = adress;
return *this;
}
operator Student() const { return student; }
private:
Student student;
};
int main()
{
Student student1 = Student::build()->adress("block Street").id(1).name("xiaoming").score(100);
student1.PrintInfo();
std::cout << "Hello World!\n";
}
C++语言 实现的构造器有个问题,就是构造的时候会执行一遍复制构造函数,导致效率低。得益于java语言的内存管理机制,java语言实现简便。C++语言的构造器还需要再继续优化。可以考虑使用move语义:
StudentBuilder& name(const string & name)
{
student.name = std::move(name);
return *this;
}
但是这种用法也存在风险:比如:
int main()
{
string adress("NewYork American");
Student student1 = Student::build()->adress(adress).id(1).name("xiaoming").score(100);
//构造完 student1 之后,student1 的内容空了
student1.PrintInfo();
std::cout << "Hello World!\n";
}
单例
某个类在运行期间,只有一个实例对外服务。要实现一个单例模式,需要做到以下两点:
- 构造函数私有。
- 全局只有一份实例,并提供获取该实例方法。
如下所示是C++代码实现的一个单列:
#include <string>
#include <iostream>
using namespace std;
class Singleton
{
public:
Singleton(const Singleton &) = delete;
Singleton &operator=(const Singleton &) = delete;
static Singleton &instance(){
static Singleton s_instance;
return s_instance;
}
string getName(){
return name_;
}
void setName(const string & name){
name_ = name;
}
private:
Singleton():name_("Singleton"){
}
~Singleton(){};
string name_;
};
int main()
{
Singleton & s = Singleton::instance();
cout << "s.name is: " << s.getName() << endl;
s.setName("Nike");
cout << "s.name is: " << s.getName() << endl;
Singleton & s1 = Singleton::instance();
cout << "s1.name is: " << s.getName() << endl;
s1.setName("Adam");
cout << "s.name is: " << s.getName() << endl;
}
程序运行结果如下所示:
s.name is: Singleton
s.name is: Nike
s1.name is: Nike
s.name is: Adam
可以看出两个单列的引用指向的是同一份实例,其中一个引用修改了内容,另一个引用去获取内容的时候会发现内容已经改变了。
工厂
工厂模式主要为创建对象提供接口,将创建对象的具体过程封装起来,从而达到提高灵活性的特点
简单工厂模式
组成简单工厂的三要素:
- 工厂类,里面有判断逻辑(if else),根据传入的参数来选择构造的对象类型