0%

面向对象(Object-Oriented ,OO)是目前从事软件开发行业的人必备的基础思维。之所以称其为“思维”而非“知识”,是因为知识是有限的、有领域(domain)的,而思维是可以无限的、创造性的、跨领域的。本文要谈的正是基于其跨领域的特性,将一些OO中最简单的基本名词,从业务管理的角度做一些发散思考。

面向对象思想的诞生

自行百度,略

业务产品中的OO

直接捞干货,本文只普及OO中的几个最基本的通用术语,并且不再赘述它们的技术定义(有兴趣的可以自行百度),用人话把这几个术语背后的思维逻辑描述一下。

类(Class)和对象(Instance)

在业务产品设计之前,第一步要做的就是把业务逻辑中那些可以认为是一个主体的“东西”抽象出来,这个主体可能是真实的(如医生、医生助理、医院等),也可能是虚拟的(如医疗服务、订单、预约等),我们称这些抽象出来的主体为

怎么判断哪些可以抽象成类呢?

  1. 拥有自己的属性或自己的行为。比如医生有姓名、职称、擅长等属性,也有看病、开检查单、上班等行为。
  2. 还要看这些属性和行为是否在自己的业务逻辑中产生作用。比如手机号虽然也有运营商、归属地等属性,但是这些属性与自己的业务没有关系,那么它就没必要抽象成类。

如果说类是我们对主体定义了一个模型,对象就是基于这个模型产生的具体实例。比如张妙手医生、二级护理服务、小李刚成交的2800元的二级护理服务的订单。

是在业务逻辑和产品设计中使用的载体,对象则是业务运行中实实在在产生的一条条数据。在业务的讨论中经常发生名词混淆,口径不统一等问题,多方对同一个名词理解有偏差,甚至根本不是一个东西,导致很多不必要的争论和误解。这些现象产生的原因就是没有准确的抽象定义清楚

抽象(Abstraction)

刚刚提到过这个术语,好的抽象就是一个建模的过程。把一个富有多种多样属性和行为的主体,抽出对业务有用的部分,不多不少,不偏不倚,还要富有兼容性和扩展性。

抽象是OO的基础,这个事跟说相声差不多。门槛特别低,按刚才说的逻辑很容易就掌握了。但是要做好也特别难,也是最考验功力的地方,因为后续所有的设计都基于抽象出来的类,尤其是在业务不断优化和拓展中,牵一发动全身,经常会出现一失足成千古恨的情况。

继承(Inheritance)

继承顾名思义,主要用来定义类的父子关系。比如我们的业务产品提供医生就诊服务、麻醉服务,护理服务。于是我们可以抽象出3个类来对应他们在业务逻辑中的主体位置。但这只是起步,OO的抽象并不仅限于此。

我们可以发现,这3个主体的属性和行为中有很多是重复的。比如都有价格、提供者、有效期等属性,都可以提供预约等。简单来说,都有医疗服务的共性。于是我们可以抽象出一个父类——医疗服务类。3个主体各自的类都作为子类继承于服务类,以此自动获得父类的特征。

这种父子关系的好处是:

  1. 将主体的共性抽象出来后,一旦对业务产品进行升级或者变动时,能够快速梳理相关的其他业务逻辑。比如当我们需要为就诊服务增加会员价格或评价机制时,马上就会想到对其他的服务也可以适用。此时,只需要在医疗服务父类增加相应的逻辑就可以了,减少了很多重复工作量。
  2. 同时还能保证子类的特殊性,比如护理服务可能是全天候的,会诊服务会提供诊断结果,麻醉服务可能是一次性的。

多态(Polymorphism)

多态是指不同子类的同一个行为是有具体差别的,是多种状态的。比如医护人员能够提供服务的行为,虽然都叫提供服务,但实际上提供的服务内容和方式都是不一样的。

于是我们在业务逻辑中可以统称为提供医疗服务,实际运营时要针对具体的服务详细定制流程和规则,并提供相应的支持。这样可以在业务逻辑设计的过程中,面对总体设计时不会被零碎的细节干扰。

封装(Encapsulation)

封装很好理解,比如业务中的医疗服务。服务内部的成本、运营、人员配合等对用户来讲是个黑盒子,我们将其封装起来,只需要提供对应的消息传递机制(message sending)就可以了。

消息传递机制由接口(interface)规则(regulation)构成

接口:就是消息传递的通道,比如服务的购买入口、咨询入口、预约入口、投诉入口;

规则:就是明确用户通过接口需要提供什么、能够获得什么。提供个人信息并在线支付价款就能获得服务;提供时间和服务凭证就能获得医生的预约;提供医生助理姓名和证据就能投诉并得到反馈。

当用户提出需求后,他并不需要知道我们是怎么满足他的,只需要给用户结果就可以了。将复杂的逻辑留给自己,将简单的动作留给用户,这就是封装最大的意义。

关联(Association)

关联形容的是类和类之间的联系,将不同类关联起来就能够组合出复杂的业务,而且每个类就向零件一样,可以更换,可以复用,为创造提供了无限的可能性。比如:

  • 多点执业可以通过医生和医院的关联实现;
  • 用户购买的诊疗服务通过用户、医生、服务类别的关联实现;
  • 就诊预约可以通过用户、订单、服务助理、医生出诊时间地点等关联实现。

关联的多种形式

当我们在定义业务产品的时候提出一个需求:每个医生需要配备医生助理,帮助医生进行患者管理工作。那么医生和医生助理之间就形成了关联。

最基本的4种关联:

  1. “一对一”:一个医生配备一个专属助理,只服务这个医生;
  2. “一对多”:一个医生配备多个专属助理,都只服务这个医生;
  3. “多对一”:一个医生配备一个助理,一个助理服务多个医生;
  4. “多对多”:一个医生配备多个助理(服务助理,跟诊助理等),一个助理可以服务多个医生。

不同的关联方式拥有不同的成本,不同的效果,不同的管理方式,不同的业务流程。同样一个最初的需求,定义什么样的解决方案,得到的结果却大不相同。

综合案例

现在我们来整体分析一个例子:

业务中目前已经提供目前麻醉服务、就诊服务等医疗服务。根据当时的业务产品定义,每个服务为一个就诊人提供服务。随着业务的发展产生了如下两个需求:

  1. 产科服务结束后,一般会向妈妈提供后续的儿科服务,有时会碰到双胞胎,于是儿科服务的就诊人就需要关联多个;
  2. 随着业务发展,公司希望开发家庭服务包,通过打包多个专业科室的医生,为一个家庭的所有成员提供服务。

基于OO的OOA(Object-Oriented Analysis):

  1. 儿科服务与产科服务都属于个体对个体的服务,都是用了就诊服务类作为模型。双胞胎概率很小,从设计角度分析,为了一些特例去改变类的属性结构和关联关系是需要慎重的。再从业务角度分析,产生这种现状的原因是当时没有清晰的定义儿科服务是否可以针对群体,如果医生的工作量会随就诊人的增加而增加,而服务收益不变,这是不合理的。所以,多个孩子(即使是双胞胎)应该购买多个儿科服务,就像上学也要交两份学费一样。而不是直接更改服务和就诊人的关联规则和设计;
  2. 家庭服务包在业务定义上是群体对群体的服务。这种服务与医生的关联关系是多对多,与就诊人的关联关系也是多对多的。于是,与原来的就诊服务类产生了本质上的不同,接下来内部预约的规则,收益的分配都因此而变的复杂和不同。如果还复用原来的就诊服务这个轮子,已经不再适合。这时就需要抽象出一个新类,来作为接下来设计业务产品的基础。

OO是产品经理的内功心法

如果某个从事技术开发的同学恰巧也看到了这篇文章,可能会觉得这些内容如此熟悉,不正是每天开发的内容么?

那就对了,OO其实就是产品经理的内功心法。从某个角度讲,一个好的产品经理必需的一个能力就是通过OO将业务产品设计和技术产品设计统一,保证方向和实施的无缝对接,协调业务和技术的高效配合。

只有内功心法还不够,还需要大杀器配合才能做到,那就是大名鼎鼎的UML(Unified Modeling Language),以后再介绍吧。
`

薛教授在《薛兆丰经济学讲义》中指出,衡量商品优质与否的标准有二

性价比匀质

客观的性价比

薛教授从生产者角度为性价比赋予了一个解释:

  1. 当生产者边际成本等于边际收益时,就是性价比最高的时候。
  2. 生产者增加的成本最终会在商品价格上转嫁给消费者。

通俗的讲,生产者倾向于多投入成本来提高商品质量,并以此获得超过更高的售价,且售价增量大于成本增量。而能不能获得这个售价取决于消费者愿不愿意支付,以获得由商品质量提高带来效用。因此:

  1. 只关注提高质量,而不考虑价格,从生产者到消费者都无法接受,那么它并不优质。
  2. 只关注降低价格,而其实只需要通过少量的成本就能大幅提升商品质量,这种商品也不是优质商品。

性价比还有主观因素

至此,薛教授谈论了性价比的客观因素。之所以称之为客观,是因为上述内容讨论的是消费者群体需求,商品的市场价值是可以衡量估算的。生产者可以基于这些信息数据来提高性价比,生产优质商品。

其实,性价比还存在着主观因素。不同消费者个体的偏好决定了其获得的边际效用,既然边际效用是主观的,性价比也就拥有了主观属性————不同人对同一个商品的性价比判断是不一样的。

匀质并不是标准

薛教授提出的衡量商品优质与否的另一个标准是匀质,即商品质量稳定,不会浮动特别大。

比如,如果一个饭店的菜每次吃都是同样的味道,同样的品质。那么这个菜,或这个饭店就显得优质。

从这个例子以及实际生活中的经验看来,确实如此。但我却不以为然,难道非匀质的商品就不优质了么?

举个极端的例子,赌石。我们知道“赌石”是极其不匀质的商品,买来的可能是价值连城的翡翠,也可能是一文不值的石头。那么我们可以说“赌石”就不是优质商品么?我觉得不能这么武断,那么匀质并不是一个真正的判断标准。

反观问题,个人觉得本质是购买非匀质的商品存在着一种成本叫“风险成本”,商品越不匀质风险成本越高。而风险成本作为成本的一部分,归根到底还是反映在性价比的判断上,并以此来衡量商品是否优质。

LDA(Linear Discriminant Analysis)

是一种监督学习的降维技术,概括来说就是“投影后类内方差最小,类间方差最大”
也可以用来分类,不过因为计算复杂,应用较少。

LDA_1

基础概念

Hermitan矩阵

满足共轭转置矩阵和自己相等的矩阵,即$A^H=A$。如果我们的矩阵A是实矩阵,则满足$A^T=A$的矩阵即为Hermitan矩阵。

瑞利商(Rayleigh quotient)

瑞利商$R(A,x)$有一个非常重要的性质,即他的最大值等于矩阵A最大的特征值,而最小值等于矩阵A的最小特征值,也就是满足:

当向量x是标准正交基时,即满足$x^Hx=1$时,瑞利商退化为:$R(A,x)=x^HAx$

广义瑞利商(generalized Rayleigh quotient)

其中x为非零向量,而A,B为n*n的Hermitan矩阵,B为正定矩阵,令$x=B^{-\frac{1}{2}}x’$,可以将其转化为瑞利商

则$R(A,B,x)$的最大最小值为矩阵$B^{-\frac{1}{2}}AB^{-\frac{1}{2}}\ 或者\ B^{-1}A$的最大最小特征值

二类LDA原理

假设

  1. 数据集$D={(x_1,y_1),(x_1,y_1),…,(x_m,y_m)}$,其中任意样本$x_i$为n维向量,$y_i\in {0,1}$;
  2. 定义$N_j(j=0,1)$为第j类样本的个数;
  3. $X_j(j=0,1)$为第j类样本的集合;
  4. $\mu_j(j=0,1)$为第j类样本的均值向量;
  5. $\Sigma_j(j=0,1)$为第j类样本的协方差矩阵(严格说是缺少分母部分的协方差矩阵)。

$\mu_j$的表达式为:

$\Sigma_j$的表达式为:

由于是两类数据,因此只需要将数据投影到一条直线上即可。假设投影直线是向量$\omega$,则:

  1. 对任意一个样本$x_i$,它在直线$\omega$上的投影为$\omega^Tx_i$;
  2. 两个类别的中心点投影为$\omega^T\mu_0和\omega^T\mu_1$;
  3. 同类样本透射电的协方差为$\omega^T\Sigma_0\omega和\omega^T\Sigma_1\omega$。

根据LDA思想,我们优化的目标即:

此时,我们一般定义类内散度矩阵$S_\omega$为

定义类间散度矩阵$S_b$为:

这样我们的优化目标重写为:

上式符合广义瑞利商的结构,符合广义瑞利商的性质,于是$J(\omega)$的最大值就是$S_\omega^{-1}S_b$的最大特征值,$\omega$就是其对应的最大特征向量!

注意到对于二分类的时候,$Sb\omega$的方向恒为$\mu_0-\mu_1$,不放零$S_b\omega=\lambda(\mu_0-\mu_1)$,将其代入$(S\omega^{-1}Sb)\omega=\lambda\omega$,可以得到$\omega=S\omega^{-1}(\mu_0-\mu_1)$,也就是说我们只要求出原始二类样本的均值和方差就可以确定最佳的投影方向$\omega$了

多类LDA原理

(未完待续)。。。

准备

安装Docker CE

选择清华的镜像网站会快一些,按步骤安装就好了

如果安装过mongodb-charts旧版本需要先卸载

docker stack rm mongodb-charts

安装mongodb-charts

创建新文件夹

mkdir mongodb-charts
cd mongodb-charts

下载最新版的Charts Docker Compose

放入新创建的文件夹中

启动 Docker Swarm

docker swarm init

拉取Charts image

docker pull quay.io/mongodb/charts:v0.10.0

使用mongo数据库账号测试连接

docker run --rm quay.io/mongodb/charts:v0.10.0 charts-cli test-connection mongodb://<username>:<password>@dds-2ze66**********26-pub.mongodb.rds.aliyuncs.com:3717,dds-2ze6653********642845-pub.mongodb.rds.aliyuncs.com:3717/admin[?replicaSet=mgset-2813849]

注意:
1. 如果是replica主从复制的库,要加上replicaSet参数
2. 连接的mongo用户需要有readWriteAnyDatabase权限

为Charts数据源库创建一个Docker secret

echo "mongodb://<username>:<password>@dds-2ze66**********26-pub.mongodb.rds.aliyuncs.com:3717,dds-2ze6653********642845-pub.mongodb.rds.aliyuncs.com:3717/admin[?replicaSet=mgset-2813849]" | docker secret create charts-mongodb-uri -

为当前用户赋予docker权限

docker守护进程启动的时候,会默认赋予名字为docker的用户组读写Unix socket的权限,因此只要创建docker用户组,并将当前用户加入到docker用户组中,那么当前用户就有权限访问Unix socket了,进而也就可以执行docker相关命令

sudo groupadd docker     #添加docker用户组
sudo gpasswd -a $USER docker     #将登陆用户加入到docker用户组中
newgrp docker     #更新用户组
docker ps    #测试docker命令是否可以使用sudo正常使用

启动Mongodb-Charts

docker stack deploy -c charts-docker-compose-v0.10.0.yml mongodb-charts

检验是否启动

docker service ls

创建Charts用户

docker exec -it \
  $(docker container ls --filter name=_charts -q) \
  charts-cli add-user --first-name "<First>" --last-name "<Last>" \
  --email "<user@example.com>" --password "<Password>" \
  --role "<UserAdmin|User>"

接下来就可以通过80端口访问mongodb-charts了

Make sure OpenSSL installed on your host

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew update
brew install openssl

Install the BI Connector

Download the MongoDB Connector for BI

tar -xvzf mongodb-bi-osx-x86_64-{version}.tgz
sudo install -m755 bin/mongo* /usr/local/bin/

Launch the BI Connector

Create schema file with mongodrdl

// mongodb without authentication
mongodrdl -d zly -o schema.drdl

// mongodb with authentication
sudo mongodrdl --host <host:port> -d <databaseName> -c <collectionName> -u opadmin -p 123456 --authenticationDatabase zlydata -o patientInfo.drdl

//--host    -h    //默认localhost
//--port     -p    //默认27017
//--db    -d    //指定database
//--collecion        -c        //指定集合,默认db中的所有集合
//--out            -o        //指定输出schema文件

//--username        -u        //用户名
//--password        -p        //密码
//--authenticationDatabase <dbname>    //指定用户创建的db
//--authenticationMechanism <name>    //指定认证机制,默认SCRAM-SHA-1

you can create lots of schema file for different collection

Starting mongosqld with a Schema File

mongosqld --schema schema.drdl

OR Starting mongosqld with a Config File

//mongosqld.config
mongodb:
  net:
    uri: dds-2ze665***********6-pub.mongodb.rds.aliyuncs.com:3717
    auth:
      username: "opadmin"
      password: "123456"
      mechanism: "SCRAM-SHA-1"
      source: "zlydata"
security:
  enabled: true
net:
  bindIp: 0.0.0.0
  port: 3307

schema:
  path: "/opt/mongo_bi/schema"
mongosqld --config mongosqld.config

OR Starting mongosqld with systemd on linux

mongosqld install --config mongosqld.config
service mongosql start

sorry, i didn’t start it successful, there’s a failure i didn’t konw why

Connect from MySQL shell

Install the C Authentication Plugin and MySQL client

  1. Download the MySQL5.7.x installer
    and install the MySQL Community Server, which includes the MySQL shell
  2. Download the C Authentication Plugin
  3. Move the file mongosql_auth.so to mysql plugin directory./lib/plugin/,you can find it by running the following command:
    mysql_config --plugindir

Connect

// mongo without authentication
mysql --protocol tcp --port 3307

// mongodb with authentication
mysql --protocol tcp --host 172.0.0.1 --port 3307 '--user=opadmin?source=zlydata' --default-auth=mongosql_auth -p

Connect from Other Client

Install the JDBC Authentication Plugin

  1. you can either download the plugin .jar file directly or use Maven
  2. save it to a local directory, and select it as a jdbc driver to de client.
  3. add the authentication plugin in the MySQL connection string:

    jdbc:mysql://127.0.0.1:3307?useSSL=false&authenticationPlugins=org.mongodb.mongosql.auth.plugin.MongoSqlAuthenticationPlugin
  4. you may also specify the authentication mechanism and authentication source as a query parameter on the username, for example:

    {username}?mechanism=PLAIN
    {username}?source={dbname}