咨询:18026285918
首页 > 新闻中心 > 面向对象 设计原则 & 松耦合设计 & 设计模式 | 吉祥物设计公司
面向对象 设计原则 & 松耦合设计 & 设计模式 | 吉祥物设计公司

1 OO 设计原则
(1) 依赖倒置 DIP: 高(稳定)/低(变化) 层模块应依赖于 抽象 (稳定)
=> 面向 `接口` 编程

实现 `高内聚, 松 耦合`

依赖倒置原则.jpg

(2) 开放封闭 OCP: 对 扩展/修改 开放/封闭
=> `需求变更时, 扩展 以满足`

(3) 单一职责 SRP: 引起(类)变化 的 原因只有1个, 变化方向 隐含着(类的)责任
(4) Liskov 替换: is a 关系, 子类 可以扩展 但 不能 更改 父类功能
(5) 接口 隔离: interface 应 小而完备
(6) 优先使用 Composition (低耦合), 而不是 Inheritance(破坏 封装)
(7) 封装 变化点: 用封装 创建 对象间 分界层, 层次 间 松耦合 => 一侧修改, 不影响 另一侧
2 松耦合 设计: ptr / ref 指向 多态对象

`设计模式 中, 基本都有 Delegation`

`ptr 表达间接, 具有灵活性: 指针 可指向 obj of B hierarchy`

class A
{
B* pB;
};

设计模式 何时用
重构 -> 分离 变化点 与 稳定点 -> 变化点 用 设计模式
3 23 种 设计模式 Key Points
创建型
(1) Factory Method: 延迟 Product 类的创建到工厂子类
(2) Abstract Factory:Factory Method 上, 引入 Product 类家族
(2) Singleton 单例: 确保 类 只有 1个实例, 提供 全局访问
(4) Prototype 原型: 用 原型 instance 指定 创建对象 的 type, clone 原型 以 创建 新对象
行为型
(1) Observer 观察者: 目标(subject) 变化时, notify 其中所含 observers 去 update
(2) Template Method: NVI(non-vf 调 vf) 手法, 先构建 框架(non-vf), 将 细节(vf) 延迟 到具体子类去实现
(3) Strategy: 使 算法族 在 client 使用时 能 独立改变
结构型
(1) Decorator: 动态 扩展 功能
(2) Bridge: 解耦 抽象(is a) 与 实现(has a), 使 两者可 独立变化
(3) Adapter: 将类的 接口转换 成 client 期望的另一接口, 解决 兼容性 问题
(4) Proxy: 用代理控制 对该对象的访问
(5) Flyweight 享元: 共享 以支持大量 小尺度 对象
(6) Facade 外观: 为 子系统 中 一组接口 提供 一致外观
(7) Composite 组合: 树状结构, 使 client 可统一处理 单个对象 和 对象组合
设计模式 间 关联
(1) Factory Method
[1] 与 Template Method: new object 像 Template Method 实现算法 一样
[2] 与 Abstract Factory: 只是 没关注 class family
(2) Template Method
[1] 与 Factory Method
[2] 与 Strategy: 用 Inheritance / delegation 改变 part of 算法 / 整个算法

(3) Proxy

[1] 与 Adapter

`是否改变` 源类 `Interface` : 否 / 是

[2] 与 Decorator

1] 加以 `控制`

2] `增强` 功能

(4) Decorator / Bridge

均解决
`Inheritance` 导致的 `类膨胀 / 扩展 不灵活问题`

思路不同

2 从 C++ 到 java
相似之处

[1] ptr 在 java 中 像 C++ 中 ref

pA->data <=> (*pA).data -> a.data

[2] override

继承 vf 自然实现 / 用 @Override

[3] 虚基类 / 接口

class RealImage: public Image
class RealImage implements Image

[4] java 中 class / mem of class 均可用 public

1 Factory Method ( 2 ways ) & OOD 常用 设计思路

不用 Factory Method.png

Factory Method: 双 class 体系 .png

Factory Method: static mem func.png

创建 子类object 的标准方法
(1) 解决的问题: 解耦 client 与 ConcreteProduct

(2) 两种方法
[1] 双 class 体系
[2] static mem func // static 目的: 用 class name
(1) 不用 Factory Method

#include

// — 1. Product hierarchy
class AP // AbstractProduct
{
public:
virtual void vf() = 0;
};

class P1: public AP
{
public:
void vf() { }
};
class P2: public AP
{
public:
void vf() { }
};

// —2. client
int main()
{
std::vector vec;

// (1) client 与 ConcreteProduct 耦合
vec.push_back(new P1);
vec.push_back(new P2);

for (int i = 0; i < vec.size(); i++) vec[i]->vf();
}

(2) Factory Method: 双 class 体系

//—1. Product hierarchy
class AP
{
public:
virtual void vf() = 0;
};

class P1: public AP
{
public:
void vf() {}
};
class P2: public AP
{
public:
void vf() {}
};

//—2. Factory hierarchy
class AF
{
public:
virtual AP* makeP(int productId) = 0;
};

class F1 : public AF
{
public:
AP*
makeP(int productId)
{
if(productId == 1)
return new P1;
else
return new P2;
}
};

//—3. client
int main()
{
// 解耦 client 与 ConcreteProduct: 3 步曲
// 1) new ConcreteFactory, 得 AF pointer
AF* pAF = new F1;

// 2) 用 AF pointer 调 makeP(),
// 得 AP pointer
AP* pAP = pAF->makeP(1);

// 3) 用 AP pointer 调 specified mem func
pAP->vf();
}

(3) Factory Method: static mem func

#include

// —1. Product hierarchy
class AP
{
public:
static AP *makeP(int productId);

virtual void vf() = 0;
};

class P1: public AP
{
public:
void vf() { }
};

class P2: public AP
{
public:
void vf() { }
};

AP*
AP::makeP(int productId)
{
if (productId == 1)
return new P1;
else
return new P2;
}
int main()
{
std::vector vec;

// (1) 用 class name 调 static mem func 得 AP*
vec.push_back( AP::makeP(0) );
vec.push_back( AP::makeP(1) );

// (2) 用 AP* 调 vf
for (int i = 0; i < vec.size(); i++) vec[i]->vf();
}

2 Abstract Factory

Abstract Factory.png

在 Factory Method 上, 引入 Product 类家族

(1) 解决的问题: 多 platforms, 每 platform 多 Product, 想封装 平台的独立性

client 每次直接 new ConcreteProduct 时, 必须 区分 Platform

解决: 加 中介层 Factory hierarchy
可把 Platform 的差异性 往 上提1个层次到 Factory

只需在上一层次 Factory: new ConcreteFactory 时 区分 Platform

(1) not use Abstract Factory

// —2. client
class Client
{
public:
void vfWindow1()
{
//(1) client 直接 new ConcreteProduct
// => new ConcreteProduct 时, 就要 区分不同 Platform
#ifdef LINUX
Windows* apWindow[] =
{
new LinuxButton,
new LinuxMenu
};
#else // WINDOWS
Windows* apWindow[] =
{
new WindowsButton,
new WindowsMenu
};
#endif

apWindow[0]->vf();
apWindow[1]->vf();
}

// Butern Menu 换个顺序 显示
void vfWindow2()
{
#ifdef LINUX
Windows* apWindow[] =
{
new LinuxMenu,
new LinuxButton
};
#else // WINDOWS
Windows* apWindow[] =
{
new WindowsMenu,
new WindowsButton
};
#endif

apWindow[0]->vf();
apWindow[1]->vf();
}
};

int main()
{
Client* pClient = new Client();
pClient->vfWindow1();
pClient->vfWindow2();
}

(2) use Abstract Factory
class Client
{
private:
Factory* pFactory;
public:
Client(Factory* pFactory1) : pFactory(pFactory1) { }

// iterface to client
void vfWindow1()
{
// (1) 用 Factory Method 去 new Product
Window* apWindow[] =
{
pFactory->makeButton(),
pFactory->makeMenu()
};

apWindow[0]->vf();
apWindow[1]->vf();
}

void vfWindow2()
{
Window* apWindow[] =
{
pFactory->makeMenu(),
pFactory->makeButton()
};

apWindow[0]->vf();
apWindow[1]->vf();
}
};

int main()
{
Factory* pFactory = NULL;

// 只需 在 new ConcreteFactory 时, 区分 不同 Platform
#ifdef LINUX
pFactory = new LinuxFactory;
#else
pFactory = new WindowFactory;
#endif

Client* pClient = new Client(pFactory);
pClient->vfWindow1();
pClient->vfWindow2();
}

3 Singleton 单例: ctor 放 private 区

Singleton 类外 ( 无法创建 单例对象 ) 调 static 接口函数 A::getInstance(), 类内 创建 且 只创建 1 个 自身 static obj, return 给 外界 作 global access

(1) 饿汉: main() 单例就已产生 => 线程安全
(2) 懒汉: 第1次使用时 才构造 => 检测 + new

非线程安全: new 底层分3步 + 多线程下线程2检测到的单例指针是线程1正在构造的半构造对象->线程2访问它, undefined behavior

`new 语句 底层分解为 3 步:
分配内存 -> pointer 强转 ( 单例 obj pointer 赋值) -> ctor`
=> `单例还没构造完, pointer 可能就已赋值

(3) 懒汉 + 锁: 线程安全, 但每次获取单例时都要阻塞, 效率低
(4) 双检测 + 锁: 想提高效率, 却导致 线程不安全 (与懒汉同问题)
`检测 -> 加锁 -> 2 次检测`

(5) 智能指针类 管理 单例对象 / 资源: 懒汉 + 锁 + SP
(6) std::call_once + std::once_flag: 保证 func 只被执行 1 次 => 线程安全
(1) once_flag 不允许修改`

(2) 多线程 同时执行 func 时, 只有1个线程 active, 其余 passive`

[1] active 线程 调 func 成功完成

其余 线程 才返回`

[2] active 线程 调 func 抛出异常

从 passive 线程 中 选1个作 新 active 线程 -> 依此类推`

(7) local static obj ( 栈 ) 实现 懒汉
`C++11: local static obj` 初始化 `线程安全`

C++11 保证
local static obj: `初始化 过程 由 第1个 线程 执行完`,

`其余线程` 在此期间 要 `等待` 第1个线程 初始化完成

// 1 饿汉
#include

class Singleton
{
public:
// (5) 类外 用 类名访问 => static interface
static Singleton*
getInstance() { return ps; }

// (6) dtor 默认
~Singleton() = default;

// (7) destory
static void
destory()
{
if (ps != NULL)
{
delete ps;
ps = nullptr;
}
}

// (8) 打印 Singleton obj addr
void printAddr() const
{
std::cout << this << "n"; } private: // (3) private ctor + 默认 ctor => 防止 外部构造
Singleton() = default;

// (4) copy delete
Singleton& operator=(const Singleton&) = delete;
Singleton(const Singleton& singleton2) = delete;

private:
// (1) static 自身 ptr
static Singleton* ps;
};

// (2) 类外 初始化 + new -> 调 private ctor
Singleton* Singleton::ps = new Singleton;

int main()
{
Singleton* ps1 = Singleton::getInstance();
ps1->printAddr();

Singleton* ps2 = Singleton::getInstance();
ps2->printAddr();

Singleton::destory();
}

// 2 懒汉: 检测 + new
static Singleton*
getInstance()
{
if (ps == nullptr)
ps = new Singleton;
return ps;
}

// 3 懒汉 + 锁 ( => 线程安全 )
static Singleton*
getInstance()
{
std::lock_guard lock(mutex_);

if (ps == nullptr)
ps = new Singleton;
return ps;
}

// 4 双检测 + 锁 // 仅列出 dif 部分
class Singleton
{
public:
// (1) dif1
static Singleton*
getInstance()
{
if (ps == nullptr)
{
std::lock_guard lock(mutex_);
if (ps == nullptr)
ps = new Singleton;
}
return ps;
}

private:
// (2) dif2
static std::mutex mutex_;
};

// (3)dif3: static mem data: 类外 初始化
Singleton* Singleton::ps = nullptr;
std::mutex Singleton::mutex_;

#include
#include
#include

void thread_func1()
{
Singleton* s1 = Singleton::getInstance();
s1->printAddr();
}

void thread_func2()
{
Singleton* s2 = Singleton::getInstance();
s2->printAddr();
}

int main()
{
std::thread t1(thread_func1);
std::thread t2(thread_func2);

t1.join();
t2.join();

Singleton::destory();
}

// 5 懒汉 + 锁 + SP
#include // std::unique_ptr
#include // std::lock_guard / std::mutex

class Singleton
{
public:
static Singleton& // def1: 返回 ref
getInstance()
{
std::lock_guard lock(mutex_);

if (!ups)
ups.reset(new Singleton);

return *ups;
}
private:
static std::unique_ptr ups;
};
std::unique_ptr Singleton::ups;

// 6 std::once_flag + std::call_once
static Singleton&
getInstance()
{
static std::once_flag flag;

std::call_once( flag,
[&]() {
ups.reset(new Singleton);
}
);

return *ups;
}

// 7 local static obj ( 栈 ) 实现 `懒汉`
static Singleton&
getInstance()
{
static Singleton intance;
return intance;
}

4 Observer 观察者
目标对象含1组观察者(observerVec), 其值被更改时, 自身(this)作实参(让 observer 能调它的 getVal 函数来 pull data )调观察者的 update 获取目标的值
=>
Observer::update 参数为 Subject*

观察者构造时, 自身(this)作实参调目标的挂接函数 attach, 将自己挂接/注册到目标对象所含观察者容器中
=>
Observer::Ctor 参数是 Subject*
attach 参数是 Observer*

Observer.png

Observer.png

1 解决的问题

`目标 object 状态改变` 时,

`观察者` 都自动 `被 notify 并 update`

1 份 data, 多种呈现

`MVC (Model-View-Controller) 的 View 部分`
Smalltalk 中 引入了 MVC 技术, 以便 交互式 软件开发

2 机制

(1) Observer -> Subject

`register`

Observer::Observer(Subject* pSubject) {
pSubject->attach(this);
}

void Subject::attach(Observer* pObs){
vec_pObs.push_back(pObs);
}

(2) Subject -> Observers

`Push / notify`

Subject 的 `notify() 定义` 在 Observer ( 的 `update() 声明` ) 定义 `之后`

void
Subject::notify(){
for (int i = 0; i < vec_pObs.size(); ++i) vec_pObs[i]->update(this);
}

(3) Observers -> Subject`

`Pull: update / getVal`

void
Observer1::update(Subject* pSub){
std::cout << pSub->getVal() << std::endl; } 5 Strategy: 使 算法族 在 client 使用时 能 独立改变 (1) 解决的问题: 多种算法 相似 + if...else 过多 (2) 机制 算法(策略函数对象 -> 用于 回调) / func 封装 成 class hierarchy 中 可替换的class

Strategy.png

6 Template Method
(1)问题: 算法 有公共部分没有复用, 公共部分变动 时, 要 维护 2 套代码

(2)解决: NVI 手法

nonvf 调 vf
`delay 算法 变化部分` 到 `子类` 去 implement
`父类` 放一 `占位函数 vf ( 公共 interface )` 被 `non-vf 调用`

(3) a real example: Windows OS 打开文件 框架
https://www.jianshu.com/p/0f209eb83f47

Template Method.png

Template Method.png

7 Decorator
(1) 问题: Inheritance 导致 target 类层次 膨胀

(2) 解决: 类层次 原/扩展 功能 Delegate 给 Decorator / Decorator 子类 实现

Decorator: 含原类层次基类指针, 以保持原功能; Decorator子类的vf override Decorator的vf, 来扩展

Decorator.png

8 Bridge
(1) 问题: Inheritance + 多维 ( 形状 / 颜色 ) 变化 导致 类膨胀

(2) 解决
对象 is a + has a 属性 分别 抽象成类, 分离 Inheritance 和 Delegation 使它们 独立变化, 减少 耦合

Bridge.png

9 Flyweight 享元
(1) 问题: 大量对象, 公共部分重复创建

(2)对象池: 对象 data 分离 成 固有 (shared 共享 -> 避免重复创建) / 变化 部分 => 避免 重复创建 共享部分

Flyweight.png

10 Facade 外观

makeProduct / new 从 Factory Method 的 client 侧放 ProductInterface class 的 ctor 中 + store n 个 ProductPtr

Facade.png

11 Proxy 代理

代理类拥有真正类的指针, 其内部 new 真正类, 外部只能看到代理类提供的接口(与 真正类同名)

Proxy.png

1 解决的问题

`安全 / 分布式` 等原因

client 不可直接访问 RealSubject obj

解决: 加 中间层 ProxySubject

2 应用

[1] Windows 快捷方式

[2] 支票或银行存单 是 账户中资金 的 代理

[3] 远程代理

[4] Copy-on-Write 代理

[5] ynchronization 代理

// === C++
#include
#include
using namespace std;

//—1 Interface/Subject
class Subject
{
public:
virtual void vf() = 0;
};

//—2 Implement/RealSubject
class RealSubject : public Subject
{
private:
string name;
public:
RealSubject(string name)
{
this->name = name;
loadFromDisk(name);
}
void loadFromDisk(string name){ cout << "Loading " + name << endl; } virtual void vf() { cout << "vfing " + name << endl; } }; //---3 ProxySubject: Inheritance + Delegation // access to RealSubject 委托给 ProxySubject class ProxySubject: public Subject { private: RealSubject* pRealSubject; // Delegation string name; public: ProxySubject(string name) { pRealSubject = NULL; this->name = name;
}

void vf()
{
// 4 用 ProxySubject 间接访问 RealSubject
if(pRealSubject == NULL)
{
pRealSubject = new RealSubject(name);
}
pRealSubject->vf();
}
};

int main()
{
//5 new ProxySubject
Subject* pSubject = new ProxySubject(“Image.jpg”);

//6 图像/Subject 第1次 从磁盘加载, 再显示
pSubject->vf();

//7 图像 已加载, 后续 直接显示
pSubject->vf();
}

// === java
//—————//Image.java
public interface Image {
void vf();
}

//—————RealImage.java
public class RealImage implements Image {

private String name;
public RealImage(String name){
this.name = name;
loadFromDisk(name);
}

@Override
public void vf() {
System.out.println(“vfing ” + name);
}

private void loadFromDisk(String name){
System.out.println(“Loading ” + name);
}
}

//—————ProxyImage.java
public class ProxyImage implements Image{

private RealImage realImage;
private String name;

public ProxyImage(String name){
this.name = name;
}

@Override
public void vf() {
if(realImage == null){
realImage = new RealImage(name);
}
realImage.vf();
}
}

//—————testProxy.java
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage(“test_10mb.jpg”);

// 图像将从磁盘加载
image.vf();
System.out.println(“”);
// 图像不需要从磁盘加载
image.vf();
}
}

12 Prototype 原型
(1) 解决的问题: 让 父类 clone 子类 obj

`父类 不知 子类 name, 如何 创建 ?`

子类 创建自身单例, 作原型, 构造过程中将自身(this) 注册 到 父子类共用 static 原型 pointer array => 父类就能据原型 obj ptr先获取子类类型, 再 clone 出 子类 object, 父类据

Prototype.png

#include
using namespace std;

enum Type
{
TYPE1,
TYPE2
};

class A
{
private:
static A* prototype[10];
static int prototypeNum;
public:
static A*
findAndClone(Type type)
{
for(int k = 0; k < prototypeNum; k++) if(prototype[k]->getType() == type)
return prototype[k]->clone();
}
virtual void operate()= 0;

protected:
// (3) attach : 可为 non-static mem
static void
attach(A* pA)
{
prototype[prototypeNum++] = pA;
}

virtual Type
getType() = 0;

virtual A*
clone() = 0;
};
A* A::prototype[];
int A::prototypeNum = 0;

class A1 : public A
{
private:
// Singleton
static A1 a1; // declaration

static int objectNum;

int id;

//(2) private ctor
A1()
{
//(3) attach self_ptr to Base/Derived shared static prototype array
attach(this);
id = 0;
}
public:
// (6) clone() 调 protected ctor
A* clone() { return new A1(1); }

// (5)
Type
getType() { return TYPE1; }

// (8)
void operate() { cout << "clone obj id: " << id << endl; } protected: // (7) protected ctor A1(int dummy){ id = objectNum++; } }; //(1) class 外 define + init. Derived -> 调 private ctor
A1 A1::a1;

int A1::objectNum = 1;

int main()
{
Type type = TYPE1;

// (4) 用 欲 clone 的 `子类 type identifier`
// as arg to `call 父类 static mem findAndClone
A* pA = A::findAndClone(type);

// (8)
pA->operate();
}

13 Adapter
`deque -> stack / queue`


用吉祥物为企业赋能 | 让品牌更有趣

品牌设计/吉祥物策略/吉祥物形象设计/文创衍生品设计

电话:18026285918

官网:www.zuoart.com

ZUOART DESIGN &copy; All Rights Reserved 

新闻中心

上一个新闻 下一个新闻
No:83184