写在前面的话:
一个类或对象中往往会包含别的对象。在创建这种成员对象时,你可能习惯使用常规的方法,即用new关键字和构造函数创建实例。但这样问题在于会导致两个类之间产生依赖性。消除这两个类之间的依赖模式,可以使用一种方法来决定究竟要实现哪个具体类。
用简单工厂模式实现计算器
UML类图:
代码中使用的工具类
/* subClass继承superClass */
extend: function(subClass, superClass) {
var F = function() {};
F.prototype = superClass.prototype;
subClass.prototype = new F(); //为子类设置原型对象
subClass.prototype.constructor = subClass;
subClass.superclass = superClass.prototype;
if(superClass.prototype.constructor === Object.prototype.constructor) {
superClass.prototype.constructor = superClass;
}
}
};
简单工厂使用一个类(通常是一个单体)来生成实例。
var OperationFactory = {
//根据传递的参数创建相应的运算符对象并返回
createOperation: function(operate) {
var oper = null;
switch(operate) {
case '+':
oper = new OperationAdd();
break;
//...
}
return oper;
}
};
业务的封装
Operation运算类
function Operation() {
//私有属性 参与运算的数字
var number1, number2;
//公有方法 属性的取值器和赋值器
this.getNumber1 = function() {
return number1;
};
this.setNumber1 = function(number) {
number1 = number;
};
this.getNumber2 = function() {
return number2;
};
this.setNumber2 = function(number) {
number2 = number;
};
}
//公有方法
Operation.prototype = {
//虚函数 需要子类实现
getResult: function() {
var result = 0.0;
return result;
}
};
各种运算符类(+ - * /)继承运算类
OperationAdd.superclass.constructor.call(this); //实现继承第一步
}
Util.extend(OperationAdd, Operation); //实现继承第二步
/*
* 重写超类的方法
* @override
*/
OperationAdd.prototype.getResult = function() { //扩展子类
var result = this.getNumber1() + this.getNumber2();
return result;
};
function OperationSub() { //'-'
OperationSub.superclass.constructor.call(this);
}
Util.extend(OperationSub, Operation);
//重写超类的方法
OperationSub.prototype.getResult = function() {
//...
}
function OperationMul() { //'*'
}
function OperationDiv() { //'/'
}
程序的总体结构:
//超类:运算类
function Operation() {
//...
}
//公有方法
Operation.prototype = {
//虚函数 需要子类实现
getResult: function() {}
};
//-----------------------------------------------------------------
//各种运算符类(+ - * /)继承运算类
最近我们公司的iClient产品需要改动,由于我们的包大概有1M了,用户在使用的过程中如果网速不是很好的话,加载的就比较慢,用户体验就不好,上面要求用户初始化的时候只有基础包,比较小,当用户用到哪一块功能就加载哪块的功能,这样体验上要好得多,但是我们的用户已经有很多了,那么我们就不能让用户改变以前的代码,只能让用户把包替换一下,这里研究了几天研究了一种办法和大家分享一下。对于做产品的朋友可能会有帮助吧!
对于产品包来说,无非就是N多的类。用户一般使用的时候都是new一个对象,然后开始使用它!比如我们有一个Person类,这里就会涉及到当浏览器运行到var person = new Person()这里时,其实内存里面还没有这个类,我们并没有在一开始就导进来,但是如果没有的话浏览器肯定会报错,那我们在new之前加一句代码来导包,这样不就是需要更改用户的源代码了吗?肯定不可取。我们需要在浏览器new对象的时候把对应的类导进来,而又不改变任何源代码,如何做到?
我们可以在基础包里面对每一个类写一个假的类,但是命名空间、类名必须都是一样的,但类里面除了构造函数什么都没有,这样假类就很小,基本不会使基础包的大小改变多少,这样在浏览器运行到如var person = new Person()这一句的时候至少不会报告错误,但是生成的对象person是假的,不可用的,我们得想办法让它变成真的,怎么才能让new出的对象不是自己而是其他的对象呢?
我尝试了很多种办法,比如在构造函数里面改变过this.__proto__.constructor、this.__proto__、this等手段,希望最后new出来的对象不是自身,而和new Person(真的)一样,但是你可以调试发现没法做到一模一样,最后无意间发现在构造函数里面使用return就可以改变new出来的对象,如下面new Person()出一个对象。
{
return new Date();
}
你会发现new出来的不是Person的对象,而是一个Date对象,而且和new Date()出来的对象一模一样,这是js这门语言故意这样设计吧!也不知道最开始的目的是啥!如果使用return;或者return null;最后new出来的对象还是本身。这样第一个问题就解决了,可以new出一个非自身的对象。
继续讨论,现在我们new出来的对象需要时真的那个类,而不是那个假的类,但是两个类的命名空间和类名都是一样的,这可怎么办,其实大家都知道所有的类无非就是window的属性而已,其实都是指针,我把指向的部分改变后不久实现了吗?
我们先需要写一个真的类,创建一个Person.js文件,打开后写入如下代码:
this.name = name;
this.age = age;
this.getName = function(){
return this.name;
}
this.getAge = function(){
return this.age;
}
}
这是一个真的类,有name和age两个属性以及getName()和getAge()两个方法。在在同样的文件夹下创建一个html文件,代码如下:
<head>
<title></title>
<script type="text/javascript" src="/blog_article/loadJS.js"></script>
<script type="text/javascript">
function init()
{
var person = new Person("Bill",23);
var name = person.getName();
var age = person.getAge();
alert(name + "_" + age);
}
function Person(name,age)
{
loadJS("idPerson","Person.js");
return new Person(name,age);
}
</script>
</head>
<body>
<button onclick="init()">测试</button>
</body>
</html>
这里有一个loadJS.js文件,这是一个动态同步加载js文件的一个包,我自己写的,很简单,里面的内容详见《js动态加载脚本》里面的第六种方法里有源代码,其实就一个方法loadJS(id,url)。上面代码
作者:zhanhailiang 日期:2013-03-08
MySQL专门为错误代码提供perror工具来查询错误代码的含义。
如下:
zhanhailiang@linux-06bq:/usr/local/services/mysql/bin> ./perror --help ./perror Ver 2.11, for linux2.6 (i686) This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPL license Print a description for a system error code or a MySQL error code. If you want to get the error for a negative error code, you should use -- before the first error code to tell perror that there was no more options. Usage: ./perror [OPTIONS] [ERRORCODE [ERRORCODE...]] -?, --help Displays this help and exits. -I, --info Synonym for --help. -a, --all Print all the error messages and the number. -s, --silent Only print the error message. -v, --verbose Print error code and message (default). (Defaults to on; use --skip-verbose to disable.) -V, --version Displays version information and exits. Variables (--variable-name=value) and boolean options {FALSE|TRUE} Value (after reading options) --------------------------------- ---------------------------------------- all FALSE verbose TRUE zhanhailiang@linux-06bq:/usr/local/services/mysql/bin> ./perror -s 1677 Column %d of table '%-.192s.%-.192s' cannot be converted from type '%-.32s' to type '%-.32s'
官方文档:8.13. perror:解释错误代码