创建类模式(读书笔记)

最近在读秦小波写的设计模式之禅这本书,创建类模式读完了,现在做一个读书笔记总结。创建类模式包括单例模式、原型模式、工厂方法模式、抽象工厂模式、建造者模式,它们都能提供对象的创建和管理职责。

单例模式(Singleton Pattern)

定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。简单来说就是确保这个类在整个系统中只有一个实例。单例模式通用类图如下:

1-1 Singleton.png

如何理解单例模式呢?

当在系统中,我们需要一个类有且仅有一个实例的时候,就可以考虑使用单例模式了,比如生成唯一序列号,创建一个对象需要消耗的资源过多,在整个项目中需要一个共享访问点或共享数据。单例模式有哪些优点呢?

  • 在内存中只有一个实例,减少了内存的消耗。比如一个对象需要频繁的创建与销毁。
  • 在系统中设置全局的访问点、优化和共享资源。
  • 由于只有一个实例,减少了系统的性能开销。比如创建一个对象需要消耗很多资源的时候,而又需要多次用到,这个时候使用单例模式就可以很大程度上减少系统性能的开销。

单例模式的使用是比较简单的,只要确保在系统中一个类只存在一个实例即可。

单例模式的通用源码

Java版:

public class Singleton {
    private static final Singleton singleton = new Singleton();
    // 限制产生多个对象
    private Singleton() {};
    
    // 通过该方法获得实例对象
    public static Singleton getSingleton() {
        return singleton;
    }
    
    // 类中其他方法,尽量是static.
    public static void doSomething(){};
}

Objective-C版:

+ (instancetype)sharedInstance
{
    static dispatch_once_t once;
    static id sharedInstance;
    // 通过dispatch_once限制产生多个对象
    dispatch_once(&once, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

在Java中,我们通过私有的构造函数来限制产生多个对象,在OC中通过dispatch_once来限制产生多个对象,其目的都是保证该类的实例只被实例化一次。

单例模式的扩展

单例模式要求我们只有一个实例,而有时候我们需要多个实例,这个时候就可以对单例模式进行下扩展就可以实现了,代码如下:

public class Singleton {
    // 最多能产生的实例数量
    private static int maxNumOfSingleton = 3;
    // 定义一个数组,容纳所有的实例
    private static ArrayList<Singleton> singletonList = new ArrayList<Singleton>();
    // 每个实例都有一个名字.
    private static ArrayList<String> nameList = new ArrayList<String>();
    // 当前实例化的下标值
    private static int index = 0;

    static  {
        for (int i = 0; i<maxNumOfSingleton; i++) {
            singletonList.add(new Singleton("实例"+(i+1)));
        }
    }

    private Singleton() {};
    private Singleton(String name) {
        nameList.add(name);
    }

    // 通过该方法获得实例对象
    public static Singleton getSingleton() {
        Random random = new Random();
        index = random.nextInt(maxNumOfSingleton);
        return singletonList.get(index);
    }

    // 类中其他方法,尽量是static.
    public static void doSomething(){};
}

原型模式(Prototype Pattern)

定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。简单来说就是通过复制的方式来创建新的对象。通用类图如下:

1-2 Prototype.png

如何理解原型模式呢?

原型模式的核心是一个clone方法,通过该方法进行对象的拷贝,Java提供了一个Cloneable接口来标示这个对象是可拷贝的,只需要重写clone方法就可以实现对象的拷贝。原型模式使用场景有哪些呢?

  • 资源优化场景。类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
  • 性能和安全要求的场景。通过new产生一个对象需要繁琐的数据准备或访问权限,则可以使用原型模式。
  • 一个对象多个修改者的场景。

原型模式比较简单,核心就是clone,掌握这个就可以了。*在iOS中使用原型模式需要实现NSCopying协议及其方法-(id)copyWithZone:(NSZone )zone。

注意点:Object类的clone方法是从内存中以二进制流的方式进行拷贝,重新分配一个内存块,所以构造函数是不会执行的。

原型模式通用源码

public class PrototypeClass implements Cloneable {
    @Override
    protected Object clone() throws CloneNotSupportedException {
        PrototypeClass prototypeClass = null;
        try {
            prototypeClass = (PrototypeClass) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return prototypeClass;
    }
}

工厂方法模式(Factory Pattern)

定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化推迟到子类。通用类图如下:

1-3 Factory.png

如何理解工厂方法模式呢?

一家汽车生产工厂,里面可以生产奔驰、宝马、大众,我们可以通过传入不同的类型从而决定要生产那种汽车,这就是工厂方法模式的一种应用。工厂方法模式的最大优点就是屏蔽了产品类实现的细节,我们不用关心奔驰车具体是怎么生产出来的。在iOS中我们经常会使用到numberWithBool:、numberWithChar等方法,这就是典型的工厂方法模式,传入不同的类型,得到不同的NSNumber对象。工厂方法模式的使用场景有哪些呢?

  • 工厂方法模式是new对象的一个替代品,在需要生成对象的时候都可以使用,但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码的复杂度。
  • 需要灵活的、可扩展的框架时,可以考虑使用工厂方法模式。
  • 工厂方法模式可以用在异构项目中。比如通过webservice与一个非Java的项目交互。

工厂方法模式通用源码

// 抽象产品类
public abstract class Product {
    // 产品类的公共方法
    public void method1() {
        // 业务逻辑处理
    }

    public abstract void method2();
}

public class ConcreteProduct1 extends Product {
    @Override
    public void method2() {
        // 业务逻辑处理
    }
}

public class ConcreteProduct2 extends Product {
    @Override
    public void method2() {
        // 业务逻辑处理
    }
}

// 抽象工厂
public abstract class Creator {
    // 输入参数类型使用泛型
    public abstract <T extends Product> T createProduct(Class<T> c);
}

public class ConcreteCreator extends Creator {
    @Override
    public <T extends Product> T createProduct(Class<T> c) {
        Product product = null;
        try {
            product = (Product) Class.forName(c.getName()).newInstance();
        } catch (Exception e) {
            System.out.println(e);
        }
        return (T) product;
    }
}

工厂方法模式扩展

  1. 缩小为简单工厂模式

    把抽象工厂给去掉,只留一个具体的工厂,这就可以称之为简单工厂方法模式了,简单工厂方法模式是工厂方法模式的简化。

  2. 升级为多个工厂类

    有时候在一个工厂类中会创建许多产品,这样所有的产品创建都在一个工厂类中的话,就会显得比较庞大,这个时候就可以拆分为多个工厂类,从而保持代码的简洁与清晰。

  3. 延迟初始化

    什么是延迟初始化(Lazy initialization)呢?一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。代码如下:

     public class ProductFactory {
         private static final Map<String, Product> productMap = new HashMap<String, Product>();
         public static synchronized Product createProduct(String type) throws Exception {
             Product product = null;
             if (productMap.containsKey(type)) {
                 product = productMap.get(type);
             }else {
                 if (type.equals("Product1")) {
                     product = new ConcreteProduct1();
                 }else {
                     product = new ConcreteProduct2();
                 }
                 // 同时把对象放到缓存容器中
                 productMap.put(type, product);
             }
             return product;
         }
     }
    

抽象工厂模式(Abstract Factory Pattern)

定义:为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。通用类图如下:

1-4 AbstractFactory.png

如何理解抽象工厂模式呢?

我们看下定义中有相关或相互依赖的对象,什么是相关或相互依赖的对象呢?比如汽车的左门和右门。抽象工厂模式的使用场景有哪些呢?一个对象族都有相同的约束,则可以使用抽象工厂模式。简单来说抽象工厂模式主要实现产品族的创建。

抽象工厂模式通用源码

// 产品
public abstract class AbstractProductA {
    public abstract void doSomething();
}

public abstract class AbstractProductB {
    public abstract void doSomething();
}

public class ProductALeft extends AbstractProductA {
    @Override
    public void doSomething() {
        System.out.println("生产A车左车门");
    }
}

public class ProductARight extends AbstractProductA {
    @Override
    public void doSomething() {
        System.out.println("生产A车右车门");
    }
}

public class ProductBLeft extends AbstractProductB {
    @Override
    public void doSomething() {
        System.out.println("生产B车左车门");
    }
}

public class ProductBRight extends AbstractProductB {
    @Override
    public void doSomething() {
        System.out.println("生产B车右车门");
    }
}

// 工厂
public abstract class AbstractCreator {
    // 创建A产品家族
    public abstract AbstractProductA createProductA();
    // 创建B产品家族
    public abstract AbstractProductB createProductB();
}

public class CreatorLeft extends AbstractCreator {
    /**
    * 左车门生产车间只生产各种车的左门.
    */
    @Override
    public AbstractProductA createProductA() {
        return new ProductALeft();
    }

    @Override
    public AbstractProductB createProductB() {
        return new ProductBLeft();
    }
}

public class CreatorRight extends AbstractCreator {
    /**
    * 右车门车间只生产所有车的右门.
    */
    @Override
    public AbstractProductA createProductA() {
        return new ProductARight();
    }

    @Override
    public AbstractProductB createProductB() {
        return new ProductBRight();
    }
}

public class Client {
    public static void main(String[] args) {
        AbstractCreator creatorLeft = new CreatorLeft();
        AbstractProductA aLeft = creatorLeft.createProductA();
        aLeft.doSomething();
        AbstractProductB bLeft = creatorLeft.createProductB();
        bLeft.doSomething();

        AbstractCreator creatorRight = new CreatorRight();
        AbstractProductA aRight = creatorRight.createProductA();
        aRight.doSomething();
        AbstractProductB bRight = creatorRight.createProductB();
        bRight.doSomething();
    }
}

建造者模式(Builder Pattern)

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。通用类图如下:

1-5 Builder.png

如何理解建造者模式呢?

在定义中提到了构建与表示分离,我们可以这样来理解,建造者模式关注的是零件类型和装配顺序,零件的不同装配顺序会产生不同效能的产品,这时零件就相当于构建了,不同装配顺序产生的产品就相当于表示了。比如A零件、B零件,按照AB顺序组装会产生一个产品,按照BA顺序组装会产生另外一个产品。建造者模式的使用场景有哪些呢?

  • 相同的方法,不同的顺序执行,产生不同的事件结果时。
  • 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
  • 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能。

建造者模式通用源码

public class Product {
    public void doSomething(){
        // 独立业务处理
    }
}

public abstract class Builder {
    // 设置产品的不同部分,以获得不同的产品.
    public abstract void setPart();
    // 建造产品
    public abstract Product buildProduct();
}

public class ConcreteBuilder extends Builder {
    private Product product = new Product();
    @Override
    public void setPart() {
        // 设置不同的部分
    }

    @Override
    public Product buildProduct() {
        return product;
    }
}

public class Director {
    private Builder builder = new ConcreteBuilder();
    // 构建不同的产品
    public Product getProductA() {
        builder.setPart();
        Product product = builder.buildProduct();
        return product;
    }
}

总结

工厂方法模式、抽象工厂模式、建造者模式、单例模式和原型模式都属于创建类模式,都能够提供对象的创建和管理的职责。其中单例模式与原型模式比较简单,单例模式是要保持在内存中只有一个对象,原型模式是通过复制的方式产生一个新的对象。工厂方法模式与抽象工厂模式最大的区别是:抽象工厂模式面向的是产品族,是工厂方法模式的升级版。工厂方法模式注重的是整体对象的创建方法,而建造者模式注重的是部件构建的过程,通过一步步地精确构造创建出一个复杂的对象。

国士梅花

欢迎大家关注国士梅花,技术路上与你陪伴。

guoshimeihua.jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,894评论 1 15
  • 设计模式基本原则 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。开-闭原...
    西山薄凉阅读 3,748评论 3 13
  • 前段时间,在自己糊里糊涂地写了一年多的代码之后,接手了一坨一个同事的代码。身边很多人包括我自己都在痛骂那些乱糟糟毫...
    丑小丫大笨蛋阅读 623评论 0 2
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者...
    lichengjin阅读 886评论 0 8