1、面向对象方法
(1)面向对象与面向过程的区别
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
其实就是两句话,面向对象就是高度实物抽象化、面向过程就是自顶向下的编程!
(2)面向对象设计方法的主要任务:
哪些类、类的职责、类间关系
(3)面向对象方法的五大特征:抽象、封装、继承、多态(虚函数的原理)、组合;
- 代码重用的手段(继承、组合)
- 数据抽象是一种接口和实现分离的编程技术。即只对外暴露关键信息,而不呈现具体的实现细节
- 数据封装是一种把数据和操作数据的函数捆绑在一起的机制
- 继承允许我们根据一个现有的类来定义一个新类,现有的类叫基类,新定义的类叫派生类。通过继承可以达到重用代码功能和提高执行效率的效果
- 多态和虚函数是相互关联的两个概念。多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。虚函数 是在基类中使用关键字 virtual 声明的函数。
- **组合:**对象组合即一个对象包容另一个对象,是对象相互合作关系中的一种。
4.面向对象方法的三个顶层原则:
三大法宝:1、封装变化点;2、针对抽象;3、多用组合,少用继承;耦合性的问题
- 要变化的地方要进行封装
- 针对抽象
- 少用继承 多用组合
5.面向对象方法的七大原则具体描述重述,解释、应用分析;:
SOLID :S:单一职责;O:开闭;L:Liskov替换;I:接口隔离;D:依赖倒置;最少知识原则, Rule of Demeter;(7)合成复用原则;
- 单一职责原则(single):它规定一个类应该只有一个发生变化的原因;
- 开闭原则(open):应该对于扩展是开放的,但是对于修改是封闭的”;
- 里氏替换原则(L:Liskov):子类应当可以替换父类并出现在父类能够出现的地方,公共的方法子类不应该重写,虚函数的方法子类应该就行重写;
- 接口隔离:一个类对另一个类的依赖应该建立在最小的接口上,不应该将多个接口绑定在一起,强迫调用;
- 依赖倒置:高层模块不应该依赖底层模块,二者都应该依赖抽象,有点类似于core里边的Interface类
抽象应该只依赖接口,不依赖实现;依赖倒置的中心思想是面向接口编程。依赖倒置原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础搭建的架构要稳定的多。使用接口或抽象类的目的是指定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类来完成。
- 最少知识原则:一个类对于其他类知道的越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话;
- **合成复用原则:**在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现
6.代表性设计模式思路理解与应用:单例、策略、简单工厂、工厂、观察者、装饰;
- 单例模式
//饿汉模式
class Singleton(){
private:
Sinleton(){}; //私有化构造函数,使得外部无法直接实例化得到一个对象
static Singleton* P_Hungry; //静态指针指向唯一对象
public:
static Singleton* GetInstance(){
return P_Hungry;
}
}
Singleton* Singleton::P_Hungry =new Singleton();
//static变量类外 实例化,调用构造函数,分配了对象的空间
//表现得很急,还没有调用类中的GetInstance(),已经将这个类的对象实例化出来,
// P_Hungry 指向该对象
//懒汉模式
class Singleton(){
private:
Sinleton(){}; //私有化构造函数,使得外部无法直接实例化得到一个对象
static Singleton* P_Lazy;
public:
static Singleton* GetInstance(){
if(P_Lazy == NULL){
P_Lazy = new Singleton();
}
return P_Lazy;
}
}
//只有当调用这个GetInstance()函数时,才实例化一个对象,P_Lazy指向该对象
//多线程模式,构造的时候也要加锁
class Singleton(){
private:
Sinleton(){}; //私有化构造函数,使得外部无法直接实例化得到一个对象
static Singleton* P_Lazy;
static Lock lock();
public:
static Singleton* GetInstance(){
if(P_Lazy == NULL){
lock();
if(P_Lazy == NULL){
P_Lazy = new Singleton();
}
unlock();
}
return P_Lazy;
}
}
- 策略模式
工厂模式是创建型的设计模式,它接受指令,创建出符合要求的实例;它主要解决的是资源的统一分发,将对象的创建完全独立出来,让对象的创建和具体的使用客户无关。主要应用在多数据库选择,类库文件加载等。
策略模式是为了解决的是策略的切换与扩展,更简洁的说是定义策略族,分别封装起来,让他们之间可以相互替换,策略模式让策略的变化独立于使用策略的客户。
应用场景:比如图像处理中,切割,滤波[有好几种方法],卷积也有好几种方法,可以定义一个父类,子类顺序加入list中进行实施
//在披萨店,你要一个培根披萨,老板说有标准的pizza,也可以自己去做。
//原料有培根、面粉、佐料。工序有1、2、3工序,你自己去做吧。
//然后你就需要自己去做,到底放多少培根,放多少面粉,放多少佐料,
//这都你自己来决定,工序1、2、3,你是怎么实现的,都你自己决定。最后你得到了披萨。
//相当于一个白盒子的工厂,是不是用了工厂模式的都用了策略模式
class Store
{
void orderPizza(){
Pizza *p = MyPizza();
//工序都有,但是具体如何实现,由用户来确定实现;
p->prepare();
p->bak();
p->cut();
}
class MyPizza : public Pizza
{
virtual void prepare(){
//我的pizza我做主,我可以多放点肉,再多来点酱
}
virtual void bak(){
//我想烤的时间长点,这样会更脆
}
virtual void cut(){
//切块,我想切成20块,像吃西瓜片那样吃披萨
}
}
class Pizza //负责提供父类的一些公共方法,还有由子类去实现的interface
- 简单工厂模式 一个工厂生产多种产品
需要的类
(1)抽象产品类(作为个具体产品基类 、 包含共有的可显示自身产品信息的纯虚方法、 析构函数需要定义为虚函数(多态方面原因))
(2)具体产品类
(3)抽象工厂类(有创建具体产品的方法)
#include <iostream>
using namespace std;
//抽象产品
class AbstractProduct {
public:
virtual ~AbstractProduct() {}
virtual void Operation() = 0;
};
//具体产品A
class ProductA : public AbstractProduct {
public:
void Operation() { cout << "ProductA" << endl; }
};
//具体产品B
class ProductB : public AbstractProduct {
public:
void Operation() { cout << "ProductB" << endl; }
};
//简单工厂
class Factory {
public:
static AbstractProduct* CreateProduct(char product) {
AbstractProduct* ap = nullptr;
switch(product)
{
case 'A':
{
ap = new ProductA();
break;
}
case 'B':
{
ap = new ProductB();
break;
}
default:
break;
}
return ap;
}
};
//- 帮助封装
//简单工厂虽然很简单,但是非常友好地帮助我们实现了组件的封装,然后让组件外部能真正面向接口编程。
//- 解耦
//通过简单工厂,实现了客户端和具体实现类的解耦。如同上面的例子,
//客户端根本就不知道具体是由谁来实现,也不知道具体是如何实现的,
//客户端只是通过工厂获取它需要的接口对象。
//缺点
//可能增加客户端的复杂度
//如果通过客户端的参数来选择具体的实现类,那么就必须让客户端能理解各个参数所代表的具体功能和含义,这样会增加客户端使用的难度,也部分暴露了内部实现,这种情况可以选用可配置的方式来实现。
//不方便扩展子工厂
//私有化简单工厂的构造方法,使用静态方法来创建接口,
//也就不能通过写简单工厂类的子类来改变创建接口的方法的行为了。
//不过,通常情况下是不需要为简单工厂创建子类的
int main() {
AbstractProduct* aPa = Factory::CreateProduct('A');
if(aPa != nullptr)
{
aPa->Operation(); // ProductA
delete aPa;
}
AbstractProduct* aPb = Factory::CreateProduct('B');
if(aPb != nullptr)
{
aPb->Operation(); // ProductB
delete aPb;
}
return 0;
}
- 工厂模式 一个工厂生产一种产品
一个具体的工厂生产一个具体的产品
需要的类
(1)抽象产品类(作为个具体产品基类 、 包含共有的可显示自身产品信息的纯虚方法、 析构函数需要定义为虚函数(多态方面原因))
(2)具体产品类(继承抽象产品类)
(3)抽象工厂类(工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现)
(4)具体工厂类(继承于抽象工厂,实现创建对应具体产品对象的方式)
原文链接:https://blog.youkuaiyun.com/zt18786458319/article/details/127879445
#include <iostream>
class Clothing{
public:
virtual void show() = 0;
virtual ~Clothing() {}
};
class Cloes :public Clothing{
void show() {
std::cout << "I'm cloes!" << std::endl;
}
};
class Coat :public Clothing{
void show(){
std::cout << "I'm coat!" << std::endl;
}
};
class Factory{
public:
virtual Clothing* creatfactory() = 0;
virtual ~Factory() {}
};
class ShoesFactory:public Factory{
public:
Clothing* creatfactory(){
return new Cloes;
}
};
class CoatFactory :public Factory{
public:
Clothing* creatfactory(){
return new Coat;
}
};
int main(){
Factory* shoes_factory = new ShoesFactory();
Clothing * m_shoes = shoes_factory->creatfactory();
if (m_shoes)
{
m_shoes->show();
delete m_shoes;
m_shoes = NULL;
}
Factory* coat_factory = new CoatFactory();
Clothing* m_coat = coat_factory->creatfactory();
if (m_coat)
{
m_coat->show();
delete m_coat;
m_coat = NULL;
}
//std::cout << "Hello World!\n";
}
- 抽象工厂模式 一个工厂生产多种商品,但是很容易重写工厂的实现
(1)抽象产品类(作为个具体产品基类 、 包含共有的可显示自身产品信息的纯虚方法、 析构函数需要定义为虚函数(多态方面原因))
(2)具体产品类(继承抽象产品类)
(3)抽象工厂类(工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现)
(4)具体工厂类(继承于抽象工厂,实现多个创建对应具体产品对象的方式)
#include <iostream>
class Clothing{
public:
virtual void show() = 0;
virtual ~Clothing(){}
};
class Coat :public Clothing{
void show()
{
std::cout << "I'm coat!" << std::endl;
}
};
class Shoes :public Clothing{
void show(){
std::cout << "I'm shoes!" << std::endl;
}
};
class ComplexFactory{
public:
virtual Clothing* CreateCoat() = 0;
virtual Clothing* CreateShoes() = 0;
virtual ~ComplexFactory(){}
};
class ClothesFactory :public ComplexFactory{
public:
Clothing* CreateCoat(){
return new Coat();
}
Clothing* CreateShoes(){
return new Shoes();
}
};
int main(){
ComplexFactory* m_coatfactory = new ClothesFactory();
Clothing* m_coat = m_coatfactory->CreateCoat();
if (m_coat)
{
m_coat->show();
delete m_coat;
m_coat = NULL;
}
Clothing* m_shoes = m_coatfactory->CreateShoes();
if (m_shoes)
{
m_shoes->show();
delete m_shoes;
m_shoes = NULL;
}
}
- 观察者模式
当事务发生的时候,通知观察者们,有一个抽象类指针的list
- 装饰模式
想要动态的给一个对象添加功能,即希望可以根据需求对现有对象添加不同的功能,以及不同功能的相互组合。如果通过继承实现功能增加,则为了各功能的组合,需要将不同功能排列组合形成数量爆炸的一堆子类。此时可以考虑装饰模式.游戏中的人物和时装。人物可以选择穿上帽子或穿上鞋子,或者都穿上,通过方法展示穿搭结果。
实现方式:
- 抽象出一个装饰基类,类中添加一个人物类指针,在构造时传入人物类指针。
- 增加需要修饰的同名方法,在方法中通过指针调用原方法,再添加新修饰内容。
- 将装饰基类继承自人物基类,为了使传入装饰类A进行装饰的指针能够传入装饰类B进行其他装饰,并且使传入装饰类A的指针可以指向该装饰类对象。
- 实现装饰基类,实现装饰内容。
- 备注为什么装饰类中增加的方法要与被装饰方法同名呢。因为在第三步中,为了需求,传入装饰类的指针,不一定指向的是人物基类对象,也可能是另一个装饰类对象。所以为了其他装饰类中通过指针调用的原方法存在,对原方法装饰后的方法要与原方法同名。
#include<iostream>
usingnamespacestd;
//装饰模式 yzs:怎么感觉这个例子是简单工厂模式
class Car{
public:
virtual void Show(void)=0;
};
//可以走的车
class Walking_Car:public Car{
public:
void Show() {
cout<<"可以跑的车"<<endl;
}
};
class Scubaiving_Car:public Car{
public:
Scubaiving_Car(std::shared_ptr<Car> &Cat):m_Car(move(Cat)) {
}
virtual void Show() override{
cout<<"可以潜水的车"<<endl;
this->m_Car->Show();
}
private:
shared_ptr<Car>m_Car;
};
class Fly_Car:public Car{
public:
constexpr Fly_Car(shared_ptr<Car>&Cat) noexcept:m_Car(move(Cat)){
}
virtual void Show(void)override{
cout<<"可以飞的车"<<endl;
this->m_Car->Show();
}
private:
shared_ptr<Car>m_Car;//是不是主要多了一个这个指针,将man进行了封装 在工厂模式里是没有这层封装的
};
class Car_factory{
public:
shared_ptr<Car> Constructor_Walking_Car() {
return shared_ptr<Car>(newWalking_Car());
}
shared_ptr<Car> Constructor_Scubaiving_Car(shared_ptr<Car>&Cat) {
return shared_ptr<Car>(newScubaiving_Car(Cat));
}
shared_ptr<Car> Constructor_Fly_Car(shared_ptr<Car>&Cat) {
return shared_ptr<Car>(newFly_Car(Cat));
}
};
void test(void) {
Car_factory&& factory=Car_factory();
autocar=factory.Constructor_Walking_Car();
car->Show();
cout<<"------------------------------------------"<<endl;
car=factory.Constructor_Scubaiving_Car(car);
//car = move (car1);
car->Show();
cout<<"------------------------------------------"<<endl;
car=factory.Constructor_Fly_Car(car);
//car = move (car2);
car->Show();
cout<<"------------------------------------------"<<endl;
}
int main() {
test();
getchar();
return0;
}
#ifndef DECORATOR_HPP
#define DECORATOR_HPP
#include <iostream>
using namespace std;
//人物基类
class Man
{
public:
virtual ~Man(){}
virtual void Show()//用于展示
{
cout << "A man." <<endl;
}
};
//装饰器抽象类 interface
class ManWithCloth:public Man//继承自Man,为了使被装饰的对象可以传入其他装饰器进行组合装饰
{
public:
ManWithCloth(Man* pMan)
:m_pMan(pMan){}
virtual ~ManWithCloth()
{
if(NULL != m_pMan)
{
delete m_pMan;
m_pMan = NULL;
}
}
virtual void Show()//上述实现方式中的第二步
{
m_pMan->Show();//通过指针调用原指针所指对象的方法,然后添加方法进行修饰
DressUp();//对原方法增加修饰
}
virtual void DressUp() = 0;//修饰方法在实现类中实现
private:
Man* m_pMan;//是不是主要多了一个这个指针,将man进行了封装 在工厂模式里是没有这层封装的
};
//装饰器实现类 戴着帽子的
class ManWearAHat:public ManWithCloth
{
public:
ManWearAHat(Man* pMan)
:ManWithCloth(pMan){}
virtual void DressUp()
{
cout << "Wear a Hat." << endl;
}
};
class ManWearShoes:public ManWithCloth
{
public:
ManWearShoes(Man* pMan)
:ManWithCloth(pMan){}
virtual void DressUp()
{
cout << "Wear shoes." << endl;
}
};
#endif // DECORATOR_HPP
********************main.cpp*******************
#include <iostream>
#include "decorator.hpp"
using namespace std;
int main()
{
Man* pMan = new Man();
pMan->Show();
cout << "=====Wear Hat=====" << endl;
pMan = new ManWearAHat(pMan);
pMan->Show();
cout << "====Wear Shoes====" << endl;
pMan = new ManWearShoes(pMan);
pMan->Show();
delete pMan;
pMan = NULL;
return 0;
}
(7)反射机制实现思想
#include <map>
#include <iostream>
#include <string>
using namespace std;
typedef void* (*PTRCreateObject)(void);
//单例
class ClassFactory {
private:
map<string, PTRCreateObject> m_classMap ;
ClassFactory(){}; //构造函数私有化
public:
//根据类名 返回对象指针
void* getClassByName(string className){
map<string, PTRCreateObject>::const_iterator iter;
iter = m_classMap.find(className) ;
if ( iter == m_classMap.end() )
return NULL ;
else
return iter->second() ;
}
//存储创建对象的函数指针,通过map映射
void registClass(string name, PTRCreateObject method){
m_classMap.insert(pair<string, PTRCreateObject>(name, method)) ;
}
//懒汉模式i
static ClassFactory& getInstance() {
static ClassFactory sLo_factory;
return sLo_factory ;
}
};
//RegisterAction实例化一个对象就往ClassFactory增加一个实例化的方法
class RegisterAction{
public:
RegisterAction(string className,PTRCreateObject ptrCreateFn){
ClassFactory::getInstance().registClass(className,ptrCreateFn);
}
};
//通过宏定义,定义各种class的反射调用,有点类似于模板函数生成
#define REGISTER(className) \
className* objectCreator##className(){ \
return new className; \
} \
RegisterAction g_creatorRegister##className( \
#className,(PTRCreateObject)objectCreator##className)
// test class
class TestClass{
public:
void m_print(){
cout<<"hello TestClass"<<endl;
};
};
REGISTER(TestClass);
int main(int argc,char* argv[]) {
TestClass* ptrObj=(TestClass*)ClassFactory::getInstance().getClassByName("TestClass");
ptrObj->m_print();
}
(8)GRASP模式原则概述:高内聚、低耦合;
https://blog.youkuaiyun.com/wfeii/article/details/80183718
GRASP与SOLID的联系与区别
- ****防止变异(Protected Variations)😗***识别变化或不稳定的地方,在易发生变化地方创建稳定的接口;
- 低耦合(Low coupling): 分配职责时,使耦合性尽可能的低,利用这一原则评估;
- ****高内聚(High Cohesion)😗***配职责可保持较高的内聚性;
- ****创建者(Creator)😗***谁创建谁,谁包含谁,有点像qt的对象树
- ****间接性(Indirection)😗***将职责分配给中介对象,是其作为其他构件或服务之间的媒介,以避免它们之间的直接耦合,中介实现了其他构件之间的间接性。比如一个公共的单例存储所有数据;
- ****多态性(Polymorphism)😗***当相关选择或行为随类型有所不同时,使用多态操作为变化的行为类型分配职责;
- ****信息专家(Information Expert)😗***把职责分配给具有完成职责所需信息的类。
- ****纯虚构(Pure Fabrication)😗***当按照信息专家不合理的时候,可以虚构一个不存在的类,只进行数据事务处理,不进行数据存储,有点类似于一个动作类,如聚类,滤波这种,在很多设计模式中都体现了纯虚构模式,如策略模式;
- ****控制器(Controller)😗***控制器是UI层之上的第一个对象,它负责接受和处理系统操作消息,事件循环和系统消息
(9)软件体系结构:风格
-
数据流风格
管道-过滤器风格:高并发,实时性:
- 过滤器一般分为:输入过滤器,处理过滤器,输出过滤器.管道是连接过滤器的设备
- 作为过滤器之间数据流动的通道的软件部件,它的主要功能是连接各个过滤器,充当过滤器之间数据流的通道。管道具有数据缓冲以及提高过滤器之间的并行性操作的作用。
- 管道由数据缓冲区,向数据缓冲区读和写数据,判断管道为空或已满等操作定义组成.
- 任何两个过滤器,只要它们之间传送的数据遵守共同的规约就可以相连接。每个过滤器都有自己独立的输入输出接口,如果过滤器间传输的数据遵守其规约,只要用管道将它们连接就可以正常工作。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WwpyRbM6-1676965435436)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/1e7f887a-7615-49fa-98e0-deaab617188b/Untitled.png)]
批处理风格
- 每一步处理都是独立的并且每一步都是顺序执行,只有在前一步结束后才能开始下一步的处理并且数据必须是完整的,以整体的方式来传递。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jgw0mqTK-1676965435437)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/5b68d606-08fc-40c9-8ae4-4f3effadb104/Untitled.png)]
https://blog.youkuaiyun.com/qq_46801776/article/details/123069582
-
面向对象风格
- 优点: 一个对象对外隐藏了自己的信息,对象将数据与操作封装在了一起。
- 缺点: 首先需要管理大量的对象,难以确定合适的结构,另外若要调用另外一个对象,就必须要知道它的名称,而且随着继承引起的复杂度,会产生连锁反应。
- 与之形成对立的可以参考管道-过滤器风格,过滤器无需知道其他过滤器的任何信息
-
独立构件风格
进程通信体系结构风格
- 客户-服务器架构,其中服务器通常用来为一个或多个客户端提供数据服务;
- 客户端则用来向服务器发出请求,针对这些请求服务器通过同步或异步方式进行请求响应。
基于事件的隐式调用风格
- 事件的触发这并不知道那些构件会被这些事件影响到,相互保持独立,这样就不能假定构件的处理顺序,甚至不知道哪些过程会被调用,并且构建彼此之间没有连接关系,各自独立存在,通过对事件的发布和注册实现关联。订阅发布式,事件循环,MVC
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bj2i9QBn-1676965435438)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/711eedcc-d2f3-4198-9745-e49ae4693adc/Untitled.png)]
-
层次风格
分层模式
- 严格分层系统要求严格遵循分层原则,限制一层中的构件只能与对等实体以及与它紧邻的下面一层进行交互。
- 严格分层优点:修改时相对简单 缺点:效率低
- 松散分层: 松散的分层应用程序放宽了此限制,它允许构件与位于它下面的任意层中的组件进行交互(注意:交互的方向依旧未变)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xXDPmCj4-1676965435439)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/4e0d1214-24f6-4bc5-977a-2df15b739fcb/Untitled.png)]
物理分层物理层描述的却是如何把功能和组件从物理上部署到独立服务器、计算机、网络或远程位置。一般情况下,一个独立运行的服务器就是一个物理层。也有几个服务器组成一个层的情况,如集群服务器就可看作是同一个层
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5NuCfd2F-1676965435440)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/f67ca87d-716a-4d84-9054-a9d3cf4d87ad/Untitled.png)]
- 虚拟机风格:
虚拟机风格包括三个被动数据组件和一个主动组件,他们分别是被解释执行的程序,用于保存程序当前执行状态的数据组件,用于保存当前解释引擎状态的组件,以及虚拟机解释器引擎。也可以记作:存储区和解释引擎
解释器风格:
- 从功能角度划分,解释器通常由微程序和解释器引擎和存储区;
- 从基本构建角度看,包括模拟解释引擎和存储器解释器风格的连接可以看做对存储区的数据访问。
- 解释器有三种策略:传统解释器(纯粹的解释执行),基于字节码的解释器(先编译后解释执行),JIT编译器(西安部分编译后解释执行)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FUYnYH6R-1676965435440)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/e7922762-fc41-4e55-9858-7beab252a8a2/Untitled.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ECqWwyA-1676965435441)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/de457983-1d18-4caa-b1d7-2226abc1c62b/Untitled.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3f0LGhxN-1676965435441)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/28e1a824-4536-40ea-9d85-6b0269958753/Untitled.png)]
基于规则的系统
构件:工作存储区,知识库,规则解释器,规则与数据元素选择器。
连接件:对存储区的数据访问。
核心思想:将业务逻辑中可能频繁发生变化的代码从源代码中分离出来
优点: 降低了修改业务逻辑的成本,缩短了开发时间,将规则外部化,可在多个应用之间共享,对规则的改变将非常迅速并且具有较低的风险
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ka6CzTkK-1676965435441)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/b362f1e6-9d70-444d-a959-71df5d0c61c0/Untitled.png)]
-
客户机/服务器风格
胖瘦客户端
- 胖客户端:客户端执行大部分的数据处理操作.特点:较低的服务器需求。与瘦客户端对应的服务器相比,胖客户端对应的服务器不需要达到同样高的性能(因为胖客户端自己就可以完成很多业务处理).因此,可以使用非常便宜的服务器.
- **瘦客户端:客户端具有很少或没有业务逻辑.单点故障.**服务器承担了大部分的业务处理,安全问题主要集中于服务器,易于维护,但服务器一旦崩溃,所有数据都会丢失。**廉价的客户端硬件.**对客户端硬件的内存、硬盘容量以及CPU等要求不高,这也降低了客户端的功耗。
两层C/S结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ddmY3xfA-1676965435442)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/ad2f7b02-d4ae-4793-9e7e-4366fb018308/Untitled.png)]
- 构件:数据库服务器,客户机应用程序
- 连接件:经由网络的调用返回机制或者事件机制
- 优点: 适合于轻量级事务,当业务逻辑较少变化以及用户数少于100时,两层C/S架构的性能较好
- 缺点:系统伸缩性差:当用户数超过100,性能急剧恶化,互操作性差:使用DBMS所提供的私有的数据编程语言来开发业务逻辑,降低了DBMS选择的灵活性,系统管理与配置成本高:当系统升级时,每个客户端都需要随之改变
三层C/S结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aS2Lmdjz-1676965435442)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/25919c05-d8fc-456e-858f-9ed449e3a1ed/Untitled.png)]
- 优点: 在用户数目较多的情况下,三层C/S结构将极大改善性能与灵活性(通常可支持数百个甚至更多用户);允许合理地划分三层结构的功能,使之在逻辑上保持相对独立性,能提高系统和软件的可维护性和可扩展性;UI、BL、DB可以分别加以复用允许更灵活有效地选用相应的平台和硬件系统,并且这些平台和各个组成部分可以具有良好的可升级性和开放性。
- 应用的各层可以并行开发,可以选择各自最适合的开发平台和开发语言。
- 利用功能层有效地隔离开表示层与数据层,未授权的用户难以绕过功能层而非法的访问数据层,为严格的安全管理奠定了坚实的基础。
- 遗留系统移植到三层C/S下将非常容易;
- **缺点:**三层C/S结构各层间的通信效率若不高,即使分配给各层的硬件能力很强,其作为整体来说也达不到所要求的性能。
- 设计时必须慎重考虑三层间的通信方法、通信频度及数据量,这和提高各层的独立性一样是三层C/S结构的关键问题。
B/S模式