赞
踩
版权声明:本文为博主「SJMP1974」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
编辑:SJMP1974
原文出处链接:https://editor.csdn.net/md?not_checkout=1&articleId=130183336
参考链接:https://hollischuang.gitee.io/tobetopjavaer/#/menu
“面向过程”(Procedure Oriented) 是一种以过程为中心的编程思想。最典型的面向过程编程语言是 C 语言。
简而言之,“面向过程”需要将问题分解成一个一个步骤,每个步骤用函数实现,依次调用即可。
例如,最典型的用法是实现一个简单的算法,比如冒泡排序。
缺点是:代码复用性较差,不易维护。
面向对象(Object Oriented)是软件开发方法,一种编程范式。对现实世界抽象,将属性(数据)、行为(操作数据的函数或方法)封装成类。
例如:想要造一辆车,上来要先把车的各种属性定义出来,然后抽象成一个Car类。
面向对象的编程语言有Java、C#、C++、Python、Ruby、PHP等。
面向对象有三大基本特征和五大基本原则。
如何将现实世界的事物抽象成代码呢?
运用面向对象的三大基本特征,即封装、继承和多态。
封装:将客观事物抽象成类(包含属性和方法),并将类的属性和方法仅让可信的类或对象操作,对不可信的进行信息隐藏。
注:【属性】可理解为数据;【方法】可理解为操作数据的函数
例如:
对客观世界的矩形进行封装。
/** * 矩形 */ class Rectangle { /** * 方法:设置矩形的长度和宽度 */ public Rectangle(int length, int width) { this.length = length; this.width = width; } /** * 数据: 长度 */ private int length; /** * 数据: 宽度 */ private int width; /** * 方法:获得矩形面积 * * @return */ public int area() { return this.length * this.width; } }
继承:子类不用复写父类的代码,通过继承的方式,可以获得父类的所有功能,即子类继承父类。
例如:
客观世界正方形是矩形的一个特例(正方形的长和宽相等),即长方形拥有的属性和方法,正方形可以通过继承的方式获得。
/**
* 正方形,继承自矩形
*/
class Square extends Rectangle {
/**
* 设置正方形边长
*
* @param length
*/
public Square(int length) {
super(length, length);
}
}
多态:一个类的实例的相同方法在不同的情形下有不同的表现形式。
例如,动物是一个抽象类,猫咪和狗是其子类,都继承 eat() 这个方法,变量 Animal animal 指向猫的实现,调用 animal.eat(),就是猫咪吃鱼,如果变量 Animal animal 指向狗的实现,调用 animal.eat(),就是狗吃骨头。
class Animal{ public abstract void eat(){ } } class Cat extends Animal{ @Override public void eat(){ System.out.println("猫咪要吃鱼"); } } class Dog extends Animal{ @Override public void eat(){ System.out.println("狗要吃骨头"); } } public class Demo { public static void main(String[] args) { Animal animal = new Cat(); animal.eat(); } }
猫咪要吃鱼
参考:https://blog.csdn.net/qq_44823756/article/details/120535531
总结:实现多态的三个步骤
多态有什么好处?
其核心思想为:一个类,最好只做一件事,只有一个引起它的变化。通常地,就是指只有一种单一功能,不要为类实现过多的功能点。
专注地,是一个人优良的品质;同样地,单一也是一个类的优良设计。
注:不仅类的职责要单一,而且方法的职责也要单一。
其核心思想是:软件实体应该是可扩展的,而不可修改的。也就是,对扩展开放,对修改封闭的。
举例:
功能是协议在发送时失败或者超时需要重新发送。
ProtocolRequest request;
bool result = Send(request);
if (!result)
{
ReSend(request);
}
但某些协议不重要,不需要重发。
ProtocolRequest request;
bool result = Send(request);
if (!result)
{
if (request is PingRequest)
{
//do nothing
}
else
{
ReSend(request);
}
}
如果是这样写代码,就违反了开放封闭原则,因为如果之后还有类似 Ping 的协议,还需要继续修改这个方法。
重构:为ProtocolRequest类新增一个属性 NeedResend,在调用处直接以此判断:
class ProtocolRequest { public int Id { get; set; } public virtual bool NeedResend { get; } } class PingRequest : ProtocolRequest { public override bool NeedResed { get { return false; } } } //for test ProtocolRequest request; bool result = Send(request); if (!result) { if (request.NeedResend) { ReSend(request); } }
这样的话,以后新增协议,需要重发就可以重写这个属性,而不需要修改原有代码。
这就符合了开闭原则。
注:此处抛砖引玉
参考:https://www.jianshu.com/p/6e2874717805
其核心思想是:子类必须能够替换其基类,子类扩展父类的功能,但是不能改变父类原有的功能。
why?
因为不遵守里氏替换原则,程序有可能出错。例如:
//父类 class Calculator{ //父类非抽象方法 public int calculate(int data1,int data2){ return data1+data2; } } class SubCalculatot extends Calculator{ //子类违反里氏替换原则,重写了父类非抽象方法, 计算差值 @Override public int calculate(int data1,int data2){ return data1-data2; } // 其他方法 ... } // 原有业务Demo类 public static void main(String[] args){ // 原有业务逻辑,引用了父类的非抽象方法 Calculator.calculate() 计算和。 Calculator calculator = new Calculator(); calculator.calculate(); } // 此时,业务需求增加,需要在子类新增一个其他方法,供业务Demo使用 public static void main(String[] args){ // 为使用新的方法,改为使用子类实现。 Calculator calculator = new SubCalculatot(); // 原有逻辑实现发生变化,导致走了子类的逻辑,计算差值 calculator.calculate(); // 新增的业务逻辑 ... calculator.otherMethod(); } // 总结:增加新的业务逻辑,影响了原有的程序,导致错误,因此,要遵循里氏替换原则。
how?(如何做?)
其核心思想是:使用多个小的专门的接口,而不要使用一个大的总接口。避免类实现接口时,类实现了根本用不上的接口,不强迫依赖不用的方法。
其核心思想是:依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象。
例如:
在最开始的时候,PizzaStore 通过new的方式创建对象,PizzaStore 是高层组件,CheesePizza 和 ClamPizza 等具体对象是低层组件,如下图所示。
package headfirst.designpatterns.factorymethod.background; import headfirst.designpatterns.factorymethod.Pizzas.CheesePizza; import headfirst.designpatterns.factorymethod.Pizzas.ClamPizza; import headfirst.designpatterns.factorymethod.Pizzas.PepperoniPizza; import headfirst.designpatterns.factorymethod.Pizzas.Pizza; public class PizzaStore { public PizzaStore() { } public Pizza orderPizza(String type){ Pizza pizza; // ---此部分代码属于变化的部分,可能根据需求变化,需要修改这段代码,不合理--- if (type.equals("cheese")){ pizza = new CheesePizza(); }else if (type.equals("clam")){ pizza = new ClamPizza(); }else if (type.equals("pepperoni")){ pizza = new PepperoniPizza(); }else{ pizza = null; } // -------------------------------------------------------------- pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
重构后:
PizzaStore 有一个抽象方法 createPizza,子类 ChicagoPizzaStore 和 NYPizzaStore 实现了createPizza,业务在使用时,由业务决定使用哪个子类创建Pizza,PizzaStore 的 orderPizza 方法根据返回的具体Pizza(ChicagoStyleCheesePizza等等),开始制作Pizza,不同子类生产 Pizza 的制作流程由子类自己决定。
public abstract class PizzaStore { // 工厂方法,是抽象方法 abstract Pizza createPizza(String item); public Pizza orderPizza(String type) { // 工厂方法生产对象,由于抽象类无法实例化,故生产对象的任务由子类(ChicagoPizzaStore 或 NYPizzaStore 完成,也就是具体的对象生产者) Pizza pizza = createPizza(type); System.out.println("--- Making a " + pizza.getName() + " ---"); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); // 调用 other method return pizza; } //******** other method, 可由各工厂实现自己特色 ********** } public class ChicagoPizzaStore extends PizzaStore { Pizza createPizza(String item) { if (item.equals("cheese")) { return new ChicagoStyleCheesePizza(); }else return null; } } public class NYPizzaStore extends PizzaStore { Pizza createPizza(String item) { if (item.equals("cheese")) { return new NYStyleCheesePizza(); }else return null; } } public abstract class Pizza { String name; String dough; String sauce; ArrayList<String> toppings = new ArrayList<String>(); void prepare() { System.out.println("Prepare " + name); System.out.println("Tossing dough..."); System.out.println("Adding sauce..."); System.out.println("Adding toppings: "); for (String topping : toppings) { System.out.println(" " + topping); } } void bake() { System.out.println("Bake for 25 minutes at 350"); } void cut() { System.out.println("Cut the pizza into diagonal slices"); } void box() { System.out.println("Place pizza in official PizzaStore box"); } public String getName() { return name; } public String toString() { StringBuffer display = new StringBuffer(); display.append("---- " + name + " ----\n"); display.append(dough + "\n"); display.append(sauce + "\n"); for (String topping : toppings) { display.append(topping + "\n"); } return display.toString(); } } public class ChicagoStyleCheesePizza extends Pizza { public ChicagoStyleCheesePizza() { name = "Chicago Style Deep Dish Cheese Pizza"; dough = "Extra Thick Crust Dough"; sauce = "Plum Tomato Sauce"; toppings.add("Shredded Mozzarella Cheese"); } void cut() { System.out.println("Cutting the pizza into square slices"); } }
原来 PizzaStore 依赖 Pizza 的具体实现,不符合依赖倒置原则。经过重构后,PizzaStore 仅依赖 Pizza 抽象类,Pizza 的具体实现类也仅依赖抽象类 Pizza。在这个过程实现了依赖倒置,实现了高层组件与低层组件的分离。
注:原来高层组件依赖低层组件,现在高层组件仅依赖高层组件,低层组件也依赖高层组件,实现了依赖倒置。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。