设计模式-可复用面向对象软件的基础读书笔记-创建型模式

主旋律

将关于该系统使用哪些具体的类的信息封装起来
隐藏了这些类的实例是如何被创建和放在一起的


Abstract Factory 抽象工厂

意图

提供一个创建一系列相关或互相依赖对象的接口 而无需制定他们具体的类

结构图
在这里插入图片描述

协作

  1. 通常运行时创建一个ConcreteFactory类的实例
  2. 产品对象的创建延迟到子类

问题

  1. 通常难以支持新种类的产品 因为AbstractFactory确定了可以创建的产品集合 支持新的产品需要扩展该工厂接口 涉及到所有子类的改变

实现

  1. 通常工厂作为单例 通常一个产品系列只需要一个工厂
  2. 通常AbstractFactory会定义一个工厂方法(Factory Method) 具体工厂也可以使用Prototype模式来实现
    在基于原型的方法中 可以使得不是每个新的产品系列都需要一个新的具体工厂类
  3. 定义可扩展的工厂可以解决上述难以扩展的问题
    这种方法是在创建对象的接口增加一个类型参数 该参数指定创建何种对象
    这样的情况下AbstractFactory只需要一个Make即可 这就是前面在第二点中所说的基于Prototype的工厂

Builder 生成器

意图 讲一个复杂对象的构建和他的表示分离,使得同样的构建过程可以创建不同的不同的表示

结构图
在这里插入图片描述
在这里插入图片描述

协作

  1. 客户端创建Director对象 并使用他所想要的Builder进行配置
  2. 产品部件被生成 导向器会通知生成器
  3. 生成器处理导向器的请求 将部件添加到产品中
  4. 客户端从生成器检索产品

实现

  1. 需要访问之前已经构造好的部件产品 比如在构建PartB需要访问前一个步骤构建的PartA
    通常在这种情况下 生成器会返回一个子节点个导向者 然后导向者将他们回传给生成者去创建父节点
  2. 一般使用生成器生成的产品差异比较大 基本不需要公共父类
  3. Builder父类一般为缺省的空方法
    比如c++中不声明为纯虚函数而是定义为空方法 可以是子类只定义自己感兴趣的操作

相关模式

  1. Composite通常是用Builder生成的
  2. Abstract Factory 注重多个系列的产品对象 Builder着重一步步构造一个复杂对象
    Abstract Factory 的产品是立刻返回的 Builder在最后一步返回产品

Factory Method 工厂方法

意图

定义一个用于创建对象的接口 让子类决定实例化哪一个类 是一个类的实例化延迟到子类

适用性

  1. 一个类不知道他所必须创建的对象的类的时候
  2. 一个类希望由子类来指定他所创建的对象
  3. 当类将创建对象的职责委托给多个帮助子类中的某一个
    并且你希望将哪一个帮助子类是代理者这一信息局部化时

结构图
在这里插入图片描述

问题

  1. 仅仅为了创建一个新的ConcreteProduct就需要一个新的ConcreteCreator子类
  2. 子类非必须时 客户端也要处理类演化的其他方面

效果

  1. 可以为子类增加钩子hook
  2. 连接平行层次的类

实现

  1. 父类工厂方法可以不提供实现 也可以提供默认的缺省实现
  2. 参数化工厂方法 根据参数可以获取不同Product
  3. lazy initialize 如果产品存在则访问 不存在则调用工厂方法
    if (_Product == 0) {
    	_Product = new CreateProduct();
    }
    return _Product;
    
  4. 使用模板可以避免创建子类解决1的问题

相关模式

  1. Abstract Factory 经常使用 Factory Method 工厂方法
  2. 工厂方法也通常在 Template Methods 中被调用
  3. Prototype不需要创建Creator子类
    但是通常需要一个针对Product的initialize操作 Creator使用initialize初始化

Prototype 原型

意图

用原型实例指定创建对象的种类 并通过拷贝构造这些原型创建新的对象

结构

在这里插入图片描述

效果

  1. 可以在运行时刻增加产品和删除产品 只在增加和删除对应的原型即可
  2. 改变原型prototype的值就可以指定新对象 客户端可以将职责委托给新的原型表现出不同的类特征
  3. 相比Factory Method可以减少子类的构造 比如减少了Creator的数量
  4. 用类动态配置应用 通过增删原型实例

问题

  1. 原型必须有clone方法 但是实现clone深拷贝 浅拷贝有时候很困难
  2. 原型数目不固定时 一般都需要一个原型管理器 用来管理原型的注册
  3. 可能有需求初始化克隆对象一般clone出一个对象obj之后可以通过一个initialize接口设定初始状态

相关模式

  1. Composite 和 Decorator 模式通过可以从 Prototype 获益

Singleton 单件(单例)

意图

保证一个类只有一个实例 并提供一个全局的访问点

结构
在这里插入图片描述

效果

  1. 严格控制访问
  2. 缩小命名空间 避免存储了唯一实例的全局变量污染名空间
  3. Singleton可以有子类
  4. 其实也可以支持可变数目的实例 这样的话也只有允许访问Singleton实例的操作需要改变
  5. 绝对比类更灵活
    另一种封装方法是使用类的静态函数 但是这样难以允许这个类有多个实例 并且静态方法子类也难以多态的冲定义

实现

  1. _instance 使用惰性初始化
    if (_instance == 0) {
    	_instance = new Singleton();
    }
    return _instance ;
    
  2. 如果用全局或静态对象做单例 依赖自动初始化 会有以下问题
    2.1 不能保证只有一个实例
    2.2 可能没有足够信息初始化
    2.3 c++没定义转换单元上全局对象的构造器的调用顺序 意味着单件之间没有依赖关系
    2.4 很小的缺点 不管你使用还是不适用 全局或者静态对象都会被创建
  3. 子类问题
    3.1 在Instance方法中可以根据不同参数实例化不同子类
    3.2 直接用继承方式 然后子类都重写Instance
    3.3 更好的方式是用单件注册表
    // 引用自书本代码
    // 引用自书本代码
    // 引用自书本代码
    class Singleton {
      public:
        static void Register(const char* name, Singleton*);
        static Singleton* Instance();
      protected:
        static Singleton* Lookup(const char*);
      private:
        static Singleton* _instance;
        static List<NameSingletonPair>* _registry;
    }
    //
    Singleton* Singleton::Instance() {
    	if (not _instance){
    		const char* singletonName = getenv("SINGLETON");
    		_instance = Lookup(singletonName);
    	}
    	return _instance;
    }
    
    MySingleton::MySingleton() {
    	Singleton::Register("MySingleton", this);
    }
    
    这里表现出来的问题是如果不实例化一个MySingleton对象 那么不会注册
    通过定义一个MySingleton的static静态实例来解决这个问题 这一点其实很尴尬的 虽然子类的职责变成了注册
    但是却一定要一定要一定要实例化创建 不然就不会注册
    static MySingleton theMySingleton;
    

嚯哈 结束了

发布了40 篇原创文章 · 获赞 0 · 访问量 2580

猜你喜欢

转载自blog.csdn.net/u010571102/article/details/103836084