设计模式1-工厂方法模式、抽象工厂模式

架构师 来源:sxyxsp123 11℃ 0评论

引言

世上本没有路,走的人多了便成了路。软件本没有什么设计模式,一个问题的解决方案使用的人和次数多了便成为了某一种设计模式..... (个人觉得,)

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。

设计模式的分类

总体来说设计模式分为三大类:

  • 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

  • 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

  • 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

设计模式的六大原则

1、开闭原则(Open Close Principle)

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科

3、依赖倒转原则(Dependence Inversion Principle)

这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

5、迪米特法则(最少知道原则)(Demeter Principle)

为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

原则是尽量使用合成/聚合的方式,而不是使用继承。

对于同一种模式,每个人的理解都不同,能解决实际问题才是关键

工厂方法模式

工厂方法模式,顾名思义工厂嘛是生产产品的,生产产品那种方式最快呢?当人是流水线作业嘛,那么怎样才能流水线生产产品呢,这些产品必须要具有相同的生产工艺和生产流程。所以工厂模式就是:工厂模式就是定义创建对象的接口(工厂),让子类决定实例化哪一个类(这些类具有一套相同接口,但是实例化的方式略有差异,即:这些接口的具体实现不同)。这样,类的实例化就推迟到了子类工厂方法模式又有简单工厂模式(工厂模式的简化版),工厂方法模式,多工厂方法模式(工厂模式的扩展)。下面我们来看看多工厂方法模式:


多工厂方法模式UML图

例子(oc版):

//创建产品的公共操作协议
@protocol DPFactoryProtocol <NSObject>

@optional

- (DPFactoryProductBaseClass *)factoryCreateProduct;

@end

//创建基类并遵守协议
@interface DPFactoryBaseClass : NSObject <DPFactoryProtocol>

@end

// 创建产品A类,可以遵守产品协议,也可以继承产品基类 需要实现产品协议中的方法
@interface DPFactoryA : NSObject <DPFactoryProtocol>

@end
#import "DPFactoryA.h"
#import "DPFactoryProductA.h"


@implementation DPFactoryA

- (DPFactoryProductBaseClass *)factoryCreateProduct{
    DPFactoryProductA * product = [[DPFactoryProductA alloc] init];
    return product;
}


@end

#import <Foundation/Foundation.h>
#import "DPFactoryProtocol.h"

// 创建产品B类,可以遵守产品协议,也可以继承产品基类 需要实现产品协议中的方法
@interface DPFactoryB : NSObject<DPFactoryProtocol>

@end
#import "DPFactoryB.h"
#import "DPFactoryProductB.h"


@implementation DPFactoryB

- (DPFactoryProductBaseClass *)factoryCreateProduct{
    DPFactoryProductB * product = [[DPFactoryProductB alloc] init];
    return product;
}


@end

#import <Foundation/Foundation.h>

//创建工厂协议
@protocol DPFactoryProductProtocol <NSObject>

@optional

- (void)productFunction;

@end

//创建工厂基类
@interface DPFactoryProductBaseClass : NSObject <DPFactoryProductProtocol>

@end

#import <Foundation/Foundation.h>
#import "DPFactoryProductProtocol.h"

//创建生产产品A的工厂, 它必须继承工厂协议或者继承工厂基类
@interface DPFactoryProductA : DPFactoryProductBaseClass

@end
#import "DPFactoryProductA.h"

@implementation DPFactoryProductA

- (void)productFunction{
    NSLog(@"我是工厂模式生产出来的A产品");
}

@end

#import <Foundation/Foundation.h>
#import "DPFactoryProductProtocol.h"

//创建生产产品B的工厂, 它必须继承工厂协议或者继承工厂基类
@interface DPFactoryProductB :DPFactoryProductBaseClass

@end
#import "DPFactoryProductB.h"

@implementation DPFactoryProductB

- (void)productFunction{
    NSLog(@"我是工厂模式生产出来的B产品");
}

@end


typedef NS_ENUM(NSInteger, ProductType) {

    ProductTypeA,
    ProductTypeB
};

//供客户使用的类
@interface DPFactoryUseForClent : NSObject

//根据客户传入的产品类型生产出相应的产品
- (DPFactoryProductBaseClass *)createProductWithProductType:(ProductType) productType;

@end
@implementation DPFactoryUseForClent

- (DPFactoryProductBaseClass *)createProductWithProductType:(ProductType) productType{

    DPFactoryProductBaseClass * product = nil;
    switch (productType) {
        case ProductTypeA:
        {
            DPFactoryA * factory = [[DPFactoryA alloc] init];
            product = [factory factoryCreateProduct];
        }
            break;
        case ProductTypeB:
        {
            DPFactoryB * factory = [[DPFactoryB alloc] init];
            product = [factory factoryCreateProduct];
        }
            break;
        default:
            break;
    }

    return product;
}

@end

 //客户端使用
    DPFactoryUseForClent * clent = [[DPFactoryUseForClent alloc]init];
    DPFactoryProductBaseClass * productA = [clent createProductWithProductType:ProductTypeA];
    [productA productFunction];

    DPFactoryProductBaseClass * productB = [clent createProductWithProductType:ProductTypeB];
    [productB productFunction];


2017-01-04 14:43:00.303 DesignPatterns[40735:3389989] 我是工厂模式生产出来的A产品
2017-01-04 14:43:00.304 DesignPatterns[40735:3389989] 我是工厂模式生产出来的B产品
抽象工厂模式

抽象工厂模式顾名思义是对工厂模式中工厂的进一步抽象,但他又不同于多工厂工厂模式,它提供一个创建一系列的相互依赖的接口,而无需指定他们具体的类。一般抽象工厂都是生成一组相互依赖的产品的,往往是多个。下面我们来看看抽象工厂模式:


抽象工厂模式UML图


例子(oc版):

@protocol DPCreateNotebookComputerProtocol <NSObject>

@optional
- (void)createNotebookComputer;

@end

@interface DPCreateNotebookComputerBaseClass : NSObject<DPCreateNotebookComputerProtocol>

@end

#import <Foundation/Foundation.h>
#import "DPCreateNotebookComputerProtocol.h"


@interface DPCreateHuaWeiNotebookComputer : DPCreateNotebookComputerBaseClass

@end
#import "DPCreateHuaWeiNotebookComputer.h"

@implementation DPCreateHuaWeiNotebookComputer

- (void)createNotebookComputer{
    NSLog(@"我是抽象工厂模式生产的华为笔记本电脑");
}

@end


#import <Foundation/Foundation.h>
#import "DPCreateNotebookComputerProtocol.h"


@interface DPIphoneNotebookComputer : DPCreateNotebookComputerBaseClass

@end
#import "DPIphoneNotebookComputer.h"

@implementation DPIphoneNotebookComputer

- (void)createNotebookComputer{
    NSLog(@"我是抽象工厂模式生产的苹果笔记本电脑");
}

@end


#import <Foundation/Foundation.h>


@protocol DPCreatePhoneProtocol <NSObject>

@optional

- (void)createPhone;

@end

@interface DPCreatePhoneBase : NSObject<DPCreatePhoneProtocol>

@end


#import <Foundation/Foundation.h>
#import "DPCreatePhoneProtocol.h"


@interface DPCreateHuaWeiPhone :DPCreatePhoneBase

@end
#import "DPCreateHuaWeiPhone.h"

@implementation DPCreateHuaWeiPhone


- (void)createPhone{
    NSLog(@"我是抽象工厂模式生产的华为手机");
}


@end


#import <Foundation/Foundation.h>
#import "DPCreatePhoneProtocol.h"

@interface DPCreateiPhone6s : DPCreatePhoneBase

@end
#import "DPCreateiPhone6s.h"

@implementation DPCreateiPhone6s

- (void)createPhone{
    NSLog(@"我是抽象工厂模式生产的苹果6s手机");
}

@end


#import <Foundation/Foundation.h>
#import "DPCreateNotebookComputerProtocol.h"
#import "DPCreatePhoneProtocol.h"


@protocol DPAbstractFactoryProtocol <NSObject>

@optional
- (DPCreateNotebookComputerBaseClass *)factoryCreateNotebookComputer;
- (DPCreatePhoneBase *)factoryCreatePhone;

@end

@interface DPFactoryBase : NSObject<DPAbstractFactoryProtocol>

@end


#import <Foundation/Foundation.h>
#import "DPFactoryProtocol.h"


@interface DPHuaWeiFactory : DPFactoryBase

@end
#import "DPHuaWeiFactory.h"
#import "DPCreateHuaWeiNotebookComputer.h"
#import "DPCreateHuaWeiPhone.h"



@implementation DPHuaWeiFactory

- (id<DPCreateNotebookComputerProtocol>)factoryCreateNotebookComputer{

    DPCreateHuaWeiNotebookComputer * computer = [[DPCreateHuaWeiNotebookComputer alloc] init];
    return computer;
}

- (id<DPCreatePhoneProtocol>)factoryCreatePhone{

    DPCreateHuaWeiPhone * phone = [[DPCreateHuaWeiPhone alloc] init];
    return phone;
}
@end


#import <Foundation/Foundation.h>
#import "DPFactoryProtocol.h"


@interface DPIPhoneFactory : DPFactoryBase

@end
#import "DPIPhoneFactory.h"
#import "DPIphoneNotebookComputer.h"
#import "DPCreateiPhone6s.h"



@implementation DPIPhoneFactory
- (id<DPCreateNotebookComputerProtocol>)factoryCreateNotebookComputer{

    DPIphoneNotebookComputer * computer = [[DPIphoneNotebookComputer alloc] init];
    return computer;
}

- (id<DPCreatePhoneProtocol>)factoryCreatePhone{

    DPCreateiPhone6s * phone = [[DPCreateiPhone6s alloc] init];
    return phone;
}
@end

#import <Foundation/Foundation.h>
#import "DPIphoneNotebookComputer.h"
#import "DPCreateiPhone6s.h"
#import "DPCreateHuaWeiNotebookComputer.h"
#import "DPCreateHuaWeiPhone.h"
#import "DPFactoryProtocol.h"
#import "DPIPhoneFactory.h"
#import "DPHuaWeiFactory.h"

typedef NS_ENUM(NSInteger, FactoryType) {
    HuaWei,
    iPhone

};

@interface DPAbstractFactoryUseForClent : NSObject

- (DPFactoryBase *)clentCreateFactoryWith:(FactoryType) FactoryType;


@end
#import "DPAbstractFactoryUseForClent.h"




@implementation DPAbstractFactoryUseForClent

- (DPFactoryBase *)clentCreateFactoryWith:(FactoryType) FactoryType{

    DPFactoryBase * factory = nil;
    switch (FactoryType) {
        case HuaWei:
        {
            factory = [[DPHuaWeiFactory alloc] init];
        }
            break;
        case iPhone:
        {
            factory = [[DPIPhoneFactory alloc] init];
        }
            break;    
        default:
            break;
    }

    return factory;

}

@end


//客户端使用
DPAbstractFactoryUseForClent * clent = [[DPAbstractFactoryUseForClent alloc] init];

        DPFactoryBase * factoryHuaWei = [clent clentCreateFactoryWith:HuaWei];

        DPCreateNotebookComputerBaseClass * huaWeiNoteBook = [factoryHuaWei factoryCreateNotebookComputer];
        [huaWeiNoteBook createNotebookComputer];

        DPCreatePhoneBase * huaWeiPhone = [factoryHuaWei factoryCreatePhone];
        [huaWeiPhone createPhone];

        DPFactoryBase * factoryiPhone = [clent clentCreateFactoryWith:iPhone];

        DPCreateNotebookComputerBaseClass * iPhoneNoteBook = [factoryiPhone factoryCreateNotebookComputer];
        [iPhoneNoteBook createNotebookComputer];

        DPCreatePhoneBase * iPhone = [factoryiPhone factoryCreatePhone];
        [iPhone createPhone];



        2017-01-04 16:37:51.545 DesignPatterns[41125:3455076] 我是抽象工厂模式生产的华为笔记本电脑
2017-01-04 16:37:51.546 DesignPatterns[41125:3455076] 我是抽象工厂模式生产的华为手机
2017-01-04 16:37:51.546 DesignPatterns[41125:3455076] 我是抽象工厂模式生产的苹果笔记本电脑
2017-01-04 16:37:51.546 DesignPatterns[41125:3455076] 我是抽象工厂模式生产的苹果6s手机

工厂模式和抽象工厂模式的比较
类族

类簇和工厂模式很类似,它通过在基类中提供工厂方法,隐藏具体的子类实现。例如Cocoa中的类方法

NSNumber * a = [NSNumber numberWithBool:YES];
    NSNumber * b = [NSNumber numberWithInteger:123];
    NSLog(@"%@",NSStringFromClass([a class])); //__NSCFBoolean
    NSLog(@"%@",NSStringFromClass([b class])); //__NSCFNumber

可以看到实际上NSNumber的Runtime类并不是NSNumber,NSNumber只是定义了一个高度抽象的基类,它既是产品类,又是工厂类。通过提供numberWith*一些列方法,隐藏了具体的子类实现。类似的还有[UIButton buttonWithType:].Cocoa中,使用类簇的设计模式有NSDictionary,NSData,NSString等。