概述
面向对象思想设计原则
在实际的开发中,我们要想更深入的了解面向对象思想,就必须熟悉前人总结过的面向对象的思想的设计原则
单一职能原则
开闭原则
里氏替换原则
依赖倒置原则
接口分离原则
迪米特原则
1.单一职能原则
单一职责原则
其实就是开发人员经常说的”高内聚,低耦合”
也就是说,每个类或每个方法都只负责一件事情。
在设计模式中,所有的设计模式都遵循这一原则
public class postive {
public static StringBuilder loadFile(String fileLocation) throws IOException {
//读取文件的内容
Reader in = new FileReader("E:\1.txt");
BufferedReader bufferedReader = new BufferedReader(in);
String line = null;
StringBuilder sb = new StringBuilder("");
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
sb.append(" ");
}
bufferedReader.close();
return sb;
}
public static String[] getWords(String regex, StringBuilder sb){
//对内容进行分割
return sb.toString().split(regex);
}
public static void main(String[] args) throws IOException {
//读取文件的内容
StringBuilder sb = loadFile("E:\1.txt");
//对内容进行分割
String[] words = getWords("[^a-zA-Z]+", sb);
System.out.println(words.length);
}
}
遵守单一原则,可以给我们带来的好处是,提高了代码的可重用性,同时还让得到的数据不再有耦合,可以用来完成我们的个性化需求。
2.开闭原则
开闭原则
核心思想是:一个对象对扩展开放,对修改关闭。
其实开闭原则的意思就是:对类的改动是通过增加代码进行的,而不是修改现有代码。
也就是说软件开发人员一旦写出了可以运行的代码,就不应该去改动它,而是要保证它能一直运行下去,如何能够做到这一点呢?这就需要借助于抽象和多态,即把可能变化的内容抽象出来,从而使抽象的部分是相对稳定的,而具体的实现则是可以改变和扩展的。
定义一个Car类:
public class Car {
private String name;
private String color;
private float price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
}
开闭原则不能在源代码上修改,定义一个DaZheCar类,继承Car类,重写setPrice方法:
public class DaZheCar extends Car {
@Override
public void setPrice(float price) {
super.setPrice(price*0.8F);
}
}
测试类:
public class MyTest {
public static void main(String[] args) {
Car car = new DaZheCar();
car.setName("宝马");
car.setColor("白色");
car.setPrice(666666F);
float price = car.getPrice();
System.out.println(price);
}
}
3. 接口隔离原则
核心思想:不应该强迫程序依赖它们不需要使用的方法。
其实就是说:一个接口不需要提供太多的行为,一个接口应该只提供一种对外的功能,不应该把所有的操作都封装到一个接口中。
一个接口中有多种方法,例如,鸟会飞,会跳,会跑等等:
public interface MyInterface {
void jump();
void fly();
void swimming();
void running();
}
而要实现的只是鸟会飞这个功能,如果实现上面的接口,就得重写所有方法,所有我们只定义一个鸟会飞的接口:
public interface FlyInterface {
void fly();
}
通过测试类去实现这个接口,从而达到只想要鸟会飞这个功能:
public class Bird implements FlyInterface {
@Override
public void fly() {
System.out.println("学会了飞");
}
}
4.依赖倒置原则
上层不能依赖于下层。
他们都应该依赖于抽象。
反例:
class Person {
public void feed(Dog dog) {
System.out.println("开始喂养");
dog.eat();
}
}
class Dog {
public void eat() {
System.out.println("狗吃骨头");
}
}
public class MyTest {
public static void main(String[] args) {
Person person = new Person();
Dog dog = new Dog();
person.feed(dog);
}
}
什么是上层,什么是下层?
调用别的方法的,就是上层,被其他方法调用的就是下层。
也就是说MyTest类中的 main方法中调用Person中的 feed(dog); 方法,那么MyTest类是上层 Perso类就是下层
Person和Dog Person中调用了Dog中的eat()方法,那么Person就是上层,Dog就是下层
现有有一个需求:需要增加一个猫类喂养:
那么我们在定义一个猫类
class Cat {
public void eat() {
System.out.println("猫吃小鱼干");
}
}
那么就又需要在Person类中提供一个重载方法:
class Person {
public void feed(Dog dog) {
System.out.println("开始喂养");
dog.eat();
}
public void feed(Cat cat) {
System.out.println("开始喂养");
cat.eat();
}
}
public class MyTest {
public static void main(String[] args) {
Person person = new Person();
Dog dog = new Dog();
Cat cat = new Cat();
person.feed(dog);
person.feed(cat);
}
}
也就是说,我每增加一个动物,都需要在Person类中提供一个重载方法
那现在就是 上层依赖于下层 也就是Person类 依赖于Dog类,Cat 类
那么下层每增加一个类,就得去修改上层,违反了依赖倒置,也就是下层一变化,上层也跟着变。
我们希望的是,当下层增加一个类时,上层应该不知道,也就是上层不应该发生变动。
正例:
class Person {
public void feed(Animal an) {
System.out.println("开始喂养");
an.eat();
}
}
abstract class Animal{
public abstract void eat();
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃小鱼干");
}
}
public class MyTest {
public static void main(String[] args) {
Person person = new Person();
Dog dog = new Dog();
Cat cat = new Cat();
person.feed(dog);
person.feed(cat);
}
}
现在我们的上层Person只依赖于Animal
下层的改动,不在影响上层
5.迪米特原则(最少知道原则)
核心思想:一个类应当对其他类知道的越少越好。
只和朋友通信。
什么是朋友?
1.类中的字段是朋友
2.方法的参数是朋友
3.方法的返回值是朋友
4.方法中实例化出来的对象是朋友
定义一个电脑类,这个类中有关机的多种操作方法,而我们需要把这个方法都统一写到另一个方法中:
class Computer {
private void saveData() {
System.out.println("保存数据...");
}
private void killProcess() {
System.out.println("关闭程序");
}
private void closeScreen() {
System.out.println("关闭屏幕");
}
private void powerOff() {
System.out.println("关闭电源");
}
public void guanji(){
this.saveData();
this.killProcess();
this.closeScreen();
this.powerOff();
}
}
定义一个人类,这个类要去进行关机操作时,只需要调用电脑类中的一个关机方法,而不需要调用多个关机操作的方法:
class Person {
Computer computer = new Computer(); //朋友
public void shutdown() {
computer.guanji();
}
public void eat(StringBuffer sb) {
String s = new String();
computer.guanji();
}
}
测试类,只需要调用人类中的关机方法,而人类中的关机方法又调用了电脑类中的关机方法:
public class MyTest {
public static void main(String[] args) {
Person person = new Person();
person.shutdown();
}
}
6. 里氏替换原则
里氏替换原则
核心思想:在任何父类出现的地方都可以用它的子类来替代。
其实就是说:子类可以随时随地替换父类对象,且替换完之后,语法不会报错,业务逻辑也不会出现问题。
需求:将长方形的宽改成比长大 1
我们先看正常情况下
class Rectangular {
private Integer width; //宽
private Integer length; //长
public Integer getWidth() {
return width;
}
public void setWidth(Integer width) {
this.width = width;
}
public Integer getLength() {
return length;
}
public void setLength(Integer length) {
this.length = length;
}
//计算面积的方法
public double getArea() {
return length * width;
}
}
//定义一个正方形的类,继承长方形
class Square extends Rectangular {
private Integer sideWidth;//边长
@Override
public Integer getWidth() {
return sideWidth;
}
@Override
public void setWidth(Integer width) {
this.sideWidth = width;
}
@Override
public Integer getLength() {
return sideWidth;
}
@Override
public void setLength(Integer length) {
this.sideWidth = length;
}
@Override
public double getArea() {
return sideWidth * sideWidth;
}
}
public class MyTest {
public static void main(String[] args) {
Rectangular rectangular = new Rectangular();
//这里可以替换成子类
rectangular = new Square();
rectangular.setWidth(20);
rectangular.setLength(15);
double area = rectangular.getArea();
System.out.println(area);
System.out.println("==============================");
}
}
特殊情况:
我再定义一个类
class Utils {
public static void transform(Rectangular graph) {
//如果宽小于等于长,就让宽加1
while (graph.getWidth() <= graph.getLength()) {
graph.setWidth(graph.getWidth() + 1);
System.out.println("长:" + graph.getLength() + " : " +
"宽:" + graph.getWidth());
}
}
}
public class MyTest {
public static void main(String[] args) {
Rectangular rectangular = new Rectangular();
//这里可以替换成子类,
//rectangular = new Square();
rectangular.setWidth(20);
rectangular.setLength(150);
System.out.println("==============================");
//传入长方形的对象,没有问题,但是传入正方形就有问题了,成死循环了。
Utils.transform(rectangular);
}
}
//这里父类就不能用子类对象来替换了,替换之后,会发生问题
要知道,在向上转型的时候,方法的调用只和new的对象有关,才会造成不同的结果。在使用场景下,需要考虑替换后业务逻辑是否受影响。
由此引出里氏替换原则的使用需要考虑的条件:
是否有is-a关系
子类可以扩展父类的功能,但是不能改变父类原有的功能。这样的反例还有很多,如:鸵鸟非鸟,还有咱们老祖宗早就说过的的春秋战国时期--白马非马说,都是一个道理。
最后
以上就是合适玉米为你收集整理的设计原则(单一职能原则,开闭原则,里氏替换原则,依赖倒置原则,接口分离原则,迪米特原则)的全部内容,希望文章能够帮你解决设计原则(单一职能原则,开闭原则,里氏替换原则,依赖倒置原则,接口分离原则,迪米特原则)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复