面向过程和面向对象
这是两个经常一起提到的概念,所谓面向过程,指的是按照我们的顺序思路,堆砌我们的代码和功能。
面向对象呢,就是把东西都当成了对象,进行对象直接的操作。那什么是对象呢,很多书籍,喜欢用生物学的逻辑去讲,这样好理解一点,大家可以自行去搜索。
我们主要探讨点就是,为什么要面向对象。原因很简单,因为是一种更高的抽象,可以站在更高的维度去看待业务需求。可以把很复杂的问题,拆分成更细小的问题去解决。也可以提高我们的代码重用率,增加系统的稳定性。
封装
封装是对象最基本的特性,对象其实就是数据和方法的集合,这个认知个人觉得还是蛮重要的。在此基础之上,还有个重要的认知就是,数据和方法都有自己的访问权限。
举例更直观(php)
class Promotion{
protected $total;
protected $discount;
//构造函数,初始化数据
function __construct($total, $discount)
{
$this ->total = $total;
$this ->discount = $discount;
}
//获得需要抵扣的金额
public function getDiscountPirce()
{
return $this->discount;
}
}
对上述的内容,做一些简单的说明
- 多了一个关键词,class
- __construct为构造函数,就是实例化后,就会首先运行的方法
- 不管是数据还是方法,会有public, protected, private的访问修饰符
注意点:把类当初一种复杂的特殊的数据类型,可以存放各种权限控制的数据,也可以有各种权限的方法。
举例更直观(java)
class Promoiton{
protected double total;
protected int discount;
//构造函数,初始化数据
public Promoiton(double $total, int $discount){
this.total = $total;
this.discount = $discount;
}
//运算对应的促销减去的金额
public double getDiscountPirce(){
return this.discount;
}
}
对上述的内容,做一些简单的说明
- 和上面的php代码对比,其实只有语法差异,比如需要定义更完善的类型等
举例更直观(python)
class Promotion:
#构造函数,初始化数据
def __init__(self, total, discount):
self._total = total
self._discount = discount
#运算对应的促销减去的金额
def getDiscountPirce(self):
return self.discount
对上述的内容,做一些简单的说明
- 有个语法特性是,参数中需要传递self关键字。
- python使用_xxx __xxx来做外部访问的控制
继承
继承主要是指子类通过语言语法特性,获得父类所有的逻辑的方式。是一种is-a的关系。
举例更直观(php)
//父类
class Promotion{
protected $total;
protected $discount;
//构造函数
function __construct($total, $discount)
{
$this ->total = $total;
$this ->discount = $discount;
}
public function getDiscountPirce()
{
return $this->discount;
}
}
/**
* 满折
*/
class FullDiscount extends promotion
{
//运行父类构造函数
function __construct($total, $discount)
{
parent::__construct($total, $discount);
}
}
对上述内容做一些简单的说明
- php采用extends关键字,做对应的继承逻辑的支持
- 子类会拥有父类的逻辑,这也会带来,修改父类代码,会影响子类的风险
举例更直观(java)
//定义促销类(满减)
class Promoiton{
protected double total;
protected int discount;
public Promoiton(double $total, int $discount){
this.total = $total;
this.discount = $discount;
}
//运算对应的促销减去的金额
public double getDiscountPirce(){
return this.discount;
}
}
//定义满折(8折传过来的值为80即可)
class FullDiscount extends Promoiton{
public FullDiscount(double $total, int $discount){
super($total, $discount);
}
}
对上述内容做一些简单的说明
- 也是采用extends关键字做的继承逻辑支持
- 构造函数中,采用了super关键字做父类构造函数调用
举例更直观(python)
class Promotion:
def __init__(self, total, discount):
self.total = total
self.discount = discount
def getDiscountPirce(self):
return self.discount
class FullDiscount(Promotion):
def getDiscountPirce(self):
return ((100 - self.discount) * self.total) / 100
对上述内容做一些简单的说明
- 继承采用的语法关键词是加上 (父类类名) 逻辑
- 父类构造不需要再用特殊关键字,会自己进行处理
综上要点说明
- 不同的语言会有不同的语法关键字对继承进行支持。但是,其实逻辑上是大同小异的。
- 继承最简单的好处就是代码的复用,当然这样也有坏的地方。所以后续我们会讲组合相关的逻辑。以及其他的设计模式对于这块逻辑的一种综述。
多态
可以简单理解为多态,就是语法支持后,继承之后对于父类同名方法的重写。对于一些动态语言,也可以非继承下,做同名方法的各自逻辑实现。
下方的更为复杂的案例,描述的业务场景,就是计算不同促销下,优惠的金额
举例更直观(php)
//父类方法(计算满减金额)
class Promotion{
protected $total;
protected $discount;
function __construct($total, $discount)
{
$this ->total = $total;
$this ->discount = $discount;
}
//计算满减的逻辑
public function getDiscountPirce()
{
return $this->discount;
}
}
/**
* 满折
*/
class FullDiscount extends promotion
{
function __construct($total, $discount)
{
parent::__construct($total, $discount);
}
//计算满折的逻辑
public function getDiscountPirce()
{
return ((100 - $this->discount) * $this->total) / 100;
}
}
/**
* 积分抵扣
*/
class IntegralDeduction extends promotion
{
function __construct($total, $discount)
{
parent::__construct($total, $discount);
}
//计算积分抵扣的逻辑
public function getDiscountPirce()
{
return $this->discount / 10;
}
}
//实例化促销类,并且计算不同类型的促销优惠
$arr = [
new Promotion(1000,30),
new FullDiscount(1000,80),
new IntegralDeduction(1000,100),
];
//计算不同的促销的金额总和
foreach ($arr as $key => $obj) {
$payment += $obj->getDiscountPirce();
}
echo $payment;
对上述内容做一些简单的说明
- 通过子类重写getDiscountPirce方法,做不同类型的促销实现,从而计算出不同的促销价。并得出总值
举例更直观(java)
class Main{
//入口函数
public static void main(String[] args) {
Promoiton[] promoitons = new Promoiton[]{
new Promoiton(1000,30),
new FullDiscount(1000, 80),
new IntegralDeduction(1000, 100),
};
System.out.println(getTotal(promoitons));
}
//计算总共需要减去的金额
public static double getTotal(Promoiton... promoitons){
double payment = 0;
for (Promoiton promoiton : promoitons){
payment = payment + promoiton.getDiscountPirce();
}
return payment;
}
}
//定义促销类(满减)
class Promoiton{
protected double total;
protected int discount;
public Promoiton(double $total, int $discount){
this.total = $total;
this.discount = $discount;
}
//运算对应的促销减去的金额
public double getDiscountPirce(){
return this.discount;
}
}
//定义满折(8折传过来的值为80即可)
class FullDiscount extends Promoiton{
public FullDiscount(double $total, int $discount){
super($total, $discount);
}
//运算对应的折扣金额
public double getDiscountPirce(){
return ((100 - this.discount) * this.total)/100;
}
}
//定义积分抵扣(积分比例为10:1)
class IntegralDeduction extends Promoiton{
public IntegralDeduction(double $total, int $discount){
super($total, $discount);
}
//运算对应的折扣金额
public double getDiscountPirce(){
return this.discount/10;
}
}
对上述内容做一些简单的说明
- 和上述的php代码相比,就一些语法格式不一样,大同小异
举例更直观(python)
class Promotion:
def __init__(self, total, discount):
self._total = total
self._discount = discount
def getDiscountPirce(self):
return self._discount
class FullDiscount(Promotion):
def getDiscountPirce(self):
return ((100 - self._discount) * self._total) / 100
class IntegralDeduction(Promotion):
def getDiscountPirce(self):
return self._discount / 10;
arr = [Promotion(1000,30), FullDiscount(1000,80), IntegralDeduction(1000,100)];
payment = 0
for obj in arr:
payment += obj.getDiscountPirce()
print(payment)
对上述内容做一些简单的说明
- 和上述的php,java代码相比,除一些语法格式不一样,一样是大同小异。也能侧面看出python代码的简洁
多态的更多实现
除了上述所描述的继承之后的重新方法,实现多态外。一般还有2种办法,可以实现多态。一是通过定义接口方法,二是duck-typing的方式
接口方法实现,后续会有详细的介绍,接口和抽象也是后续需要掌握的一个大的认知点
下面实现duck-typing的方式
class English:
def record(self):
print("hello")
class Chinese:
def record(self):
print("你好")
def test(recorder):
recorder.record()
def demo():
english = English()
chinese = Chinese()
test(english)
test(chinese)
#执行函数
demo()
#输出对应的数据
hello
你好
对上述内容做一些简单的说明
- 首先无继承关系。是各自独立的类
- 通过使用相同的方法,来进行实例化的时候。也就是类运行过程中,去使用对用的实例类中的方法
3.一般只有动态语言,支持这种方式
网友评论