设计模式-工厂模式

简单工厂模式

简单工厂模式:又叫静态工厂模式,由一个工厂对象决定创建某一种产品对象的实例。主要用来创建同一类对象。
举个例子,比如书店里有各类书籍及其相关介绍等。当你要选择其中一类书籍时你只需要问书店老板,他会向你提供你所需要的,你只需要记住BookFactory这个工厂类即可。


var StoryBook = function() {
    this.intro = "这是一本故事书。";
}
StoryBook.prototype = {
    getPageNumber() {
        console.log("一共300页。")
    },
    getBookName() {
        console.log("格林童话")
    }
};
var ReferenceBook = function() {
    this.intro = "这是一本工具书。";
}
ReferenceBook.prototype = {
    getBookName() {
        console.log("新华字典");
    },
    getPageNumber() {
        console.log("一共1000页。")
    }
}
var HistoryBook = function() {
    this.intro = "这是一本历史书。";
}
HistoryBook.prototype = {
    getBookName() {
        console.log("中华上下五千年");
    },
    getPageNumber() {
        console.log("一共3000页。")
    }
}

//工厂类
var BookFactory = function(type) {
    switch(type) {
        case "story": return new StoryBook();
        case "reference": return new ReferenceBook();
        case "history": return new HistoryBook();
    }
}

var book = BookFactory('history');
book.getBookName(); //中华上下五千年
book.getPageNumber(); //一共3000页。

如上例子,将各类书籍对象的创建封装到一个函数里面,通过这个函数就可以创建所需要的对象而不用关注这些对象时基于哪个类,这个函数通常也被称为工厂函数,这种模式叫做简单工厂模式。
简单工厂模式存在的缺点就是如果产品的种类非常多switch case的判断会变得非常多,而且它不符合开放-封闭原则,如果要增加或删除一个产品种类,就要修改switch case的判断代码。

工厂方法模式

工厂方法模式:通过对产品类的抽象使其创建业务主要负责用于创建多类产品的实例。
上面简单工厂模式的例子里面,如果此时添加一种新的书籍类别时,我们就要新增一个类,同时还要对工厂函数做出修改。

//新增一个英语书的类
var EngligshBook = function(){
    this.intro = "这是一本英语书。";
}
EngligshBook.prototype = {
    getBookName() {
        console.log("英语听力");
    },
    getPageNumber() {
        console.log("一共300页。")
    }
}

//工厂类
var BookFactory = function(type) {
    switch(type) {
        ...
        //新增英语书类创建
        case "english": return new EngligshBook();
    }
}

如果使用了工厂方法模式,我们可以将工厂方法看作是一个实例化对象的工厂类,将创建对象的基类放在工厂方法类的原型中。


function getBookName(bookname) {
    console.log(bookname)
}

//工厂类
var BookFactory = function(type,intro) {
    return new this[type](intro);
}
BookFactory.prototype = {
    StoryBook:function(intro) {
        this.intro = intro;
        getBookName("格林童话");
    },
    ReferenceBook:function(intro) {
        this.intro = intro;
        getBookName("新华字典")
    },
    HistoryBook: function(intro) {
        this.intro = intro;
        getBookName("中华上下五千年");
    },
    EngligshBook: function(intro){
        this.intro = intro;
        getBookName("英语听力");
    }

}

var book = new BookFactory('EngligshBook');

工厂方法模式本意是说实际创建对象工作推迟到子类当中。这样核心类就成了抽象类。但对于JavaScript来说没有像传统创建抽象类那样的方式轻易创建抽象类,所以在JavaScript中实现工厂方法模式只要参考其核心思想即可。如上例子,如果要添加其他的基类,只要在BookFactory这个工厂类的原型里面添加即可。

安全模式类
安全模式类是指可以屏蔽使用这对类的错误使用造成的错误。比如对于一个类的创建,如果在使用的时候忽略了通过new关键字直接执行类,此时就会造成程序报错。
基于此,安全模式类就是一个解决方案,在构造函数开始时先判断当前对象this指代的是不是类,如果是则通过new关键字创建对象,如果不是说明类在全局作用下执行,这样我们就要返回新创建的对象了。

var DemoFactory = function(type) {
    if (this instanceof DemoFactory) {
        return new this[type]();
    }else {
        return new DemoFactory('test');
    }
    
}
DemoFactory.prototype = {
    test:function() {
        console.log("demo");
    }
}
// var d = new DemoFactory('test'); //demo,this指向DemoFactory
var d = DemoFactory('test'); //demo,this指向全局

如上,当代码中忽略了new而执行了类的话,只要在工厂方法中增加this指向判断并对this指向全局的情况重新返回新创建对象,就可以避免报错,创建安全的工厂方法。

如果使用简单工厂模式,每次新增类时都需要修改工厂函数,对于创建多类对象,简单工厂模式就不太适用了,但通过工厂方法模式就可以轻松创建多个类的实例对象,这样工厂方法对象在创建对象的方式也避免了使用者与对象类之间的耦合,用户不必关心创建该对象的具体类,只需调用工厂方法即可。

抽象工厂模式

抽象工厂类:通过对类的工厂抽象使其业务用于对产品类簇的创建,而不负责创建某一类产品的实例。

抽象类

抽象类是一种声明但不能使用的类,它定义了一种类和该类所必备的方法,如果子类中没有重写这些方法,那么当调用时就会报错。在JavaScript中可以通过手动地抛出异常来模拟抽象类。
设计一个饮料抽象类,当使用该其实例对象的方法时会抛出异常:

var Drink = function(){};
Drink.prototype = {
    getPrice() {
        return new Error("抽象方法不能调用");
    },
    getName() {
        return new Error("抽象方法不能调用");
    }
}

抽象工厂模式

首先建立一个抽象工厂方法实现子类继承父类,并且在其原型上创建父类(抽象类)

var DrinkFactory = function(subType,superType) {
    if(typeof DrinkFactory[superType] === "function") {
        function F(){};
        F.prototype = new DrinkFactory[superType]();
        subType.constructor = subType;
        subType.prototype = new F();
    }else {
        throw new Error("未创建该抽象类")
    }
}
DrinkFactory.Coffee = function() {
    this.type = "coffee";
}
DrinkFactory.Coffee.prototype = {
    getName() {
        return new Error("抽象方法不能调用");
    },
    getPrice() {
        return new Error("抽象方法不能调用");
    }
}

抽象工厂方法是实现子类继承父类的方法,在这个方法中通过传递子类以及要继承的父类的名称,在这个抽象工厂方法中先是对抽象类存在性做了一次判断,如果存在则子类继承父类。在抽象类存在的情况下,首先创建一个过渡类来继承父类,在过渡类的原型继承时,是通过new关键字复制的父类的一个实例而不是继承父类的原型,主要原因是过渡类不仅要继承父类的原型方法,还要继承父类的对象属性,所以要通过new关键字将父类的构造函数执行一遍来复制构造函数中的属性和方法。
在使用抽象工厂模式时,我们先创建一个子类,通过工厂方法让子类继承父类的属性和方法,然后重写父类的方法。

var MochaCoffee = function(name,price) {
    this.name = name;
    this.price = price;
}
DrinkFactory(MochaCoffee,"Coffee");
MochaCoffee.prototype = {
    getName() {
        console.log(this.name);
    },
    getPrice() {
        console.log(this.price)
    }
}

var d = new MochaCoffee("mocha","¥30");

d.getName();
d.getPrice();

抽象工厂模式是设计模式中最抽象的一种,也是创建模式中唯一一种抽象化创建模式。该模式创建出的结果不是一个真实的对象实例,而是一个类簇,它制定了类的结构,这也就区别于简单工厂模式创建单一对象,工厂模式创建多类对象。

参考:《JavaScript设计模式》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值