最近在读秦小波写的设计模式之禅这本书,创建类模式读完了,现在做一个读书笔记总结。创建类模式包括单例模式、原型模式、工厂方法模式、抽象工厂模式、建造者模式,它们都能提供对象的创建和管理职责。
单例模式(Singleton Pattern)
定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。简单来说就是确保这个类在整个系统中只有一个实例。单例模式通用类图如下:
如何理解单例模式呢?
当在系统中,我们需要一个类有且仅有一个实例的时候,就可以考虑使用单例模式了,比如生成唯一序列号,创建一个对象需要消耗的资源过多,在整个项目中需要一个共享访问点或共享数据。单例模式有哪些优点呢?
- 在内存中只有一个实例,减少了内存的消耗。比如一个对象需要频繁的创建与销毁。
- 在系统中设置全局的访问点、优化和共享资源。
- 由于只有一个实例,减少了系统的性能开销。比如创建一个对象需要消耗很多资源的时候,而又需要多次用到,这个时候使用单例模式就可以很大程度上减少系统性能的开销。
单例模式的使用是比较简单的,只要确保在系统中一个类只存在一个实例即可。
单例模式的通用源码
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)
定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。简单来说就是通过复制的方式来创建新的对象。通用类图如下:
如何理解原型模式呢?
原型模式的核心是一个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)
定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化推迟到子类。通用类图如下:
如何理解工厂方法模式呢?
一家汽车生产工厂,里面可以生产奔驰、宝马、大众,我们可以通过传入不同的类型从而决定要生产那种汽车,这就是工厂方法模式的一种应用。工厂方法模式的最大优点就是屏蔽了产品类实现的细节,我们不用关心奔驰车具体是怎么生产出来的。在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;
}
}
工厂方法模式扩展
-
缩小为简单工厂模式
把抽象工厂给去掉,只留一个具体的工厂,这就可以称之为简单工厂方法模式了,简单工厂方法模式是工厂方法模式的简化。
-
升级为多个工厂类
有时候在一个工厂类中会创建许多产品,这样所有的产品创建都在一个工厂类中的话,就会显得比较庞大,这个时候就可以拆分为多个工厂类,从而保持代码的简洁与清晰。
-
延迟初始化
什么是延迟初始化(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)
定义:为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。通用类图如下:
如何理解抽象工厂模式呢?
我们看下定义中有相关或相互依赖的对象,什么是相关或相互依赖的对象呢?比如汽车的左门和右门。抽象工厂模式的使用场景有哪些呢?一个对象族都有相同的约束,则可以使用抽象工厂模式。简单来说抽象工厂模式主要实现产品族的创建。
抽象工厂模式通用源码
// 产品
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)
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。通用类图如下:
如何理解建造者模式呢?
在定义中提到了构建与表示分离,我们可以这样来理解,建造者模式关注的是零件类型和装配顺序,零件的不同装配顺序会产生不同效能的产品,这时零件就相当于构建了,不同装配顺序产生的产品就相当于表示了。比如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;
}
}
总结
工厂方法模式、抽象工厂模式、建造者模式、单例模式和原型模式都属于创建类模式,都能够提供对象的创建和管理的职责。其中单例模式与原型模式比较简单,单例模式是要保持在内存中只有一个对象,原型模式是通过复制的方式产生一个新的对象。工厂方法模式与抽象工厂模式最大的区别是:抽象工厂模式面向的是产品族,是工厂方法模式的升级版。工厂方法模式注重的是整体对象的创建方法,而建造者模式注重的是部件构建的过程,通过一步步地精确构造创建出一个复杂的对象。
国士梅花
欢迎大家关注国士梅花,技术路上与你陪伴。