设计模式(Java)----七大面向对象设计原则

一.单一职责原则
单一职责原则对类来说,即一个类应该只负责一项职责。
主要根据不同的角度划分职责,比如,
1、从类的组成,划分为属性操作和行为操作两种。
2、从数据库操作的不同作用,划分为数据库的连接操作和增删改查基本操作。
原例:

class Vehicle{
public void run(String vehicle) {
System.out. println(vehicle + "在公路上跑");} }
public class singleResponsibility {
public static void main(String[] args) {
Vehicle vehicle = new Vehicle(); 
vehicle.run("摩托车");
vehicle.run("汽车");
vehicle.run("飞机");}
}

原例的分析:
1.在方式1的run方法中,违反了单一职责原则。
2.解决方案:根据交通工具运行方法不同,分解成不同类。
改进:

class Vehicle2 {
	public void run(String vehicle) { // 不变
		System.out.println(vehicle + "在公路上跑");
	}

	public void runAir(String vehicle) { // 增加
		System.out.println(vehicle + "在天空中飞");
	}

	public void runWater(String vehicle) { // 增加
		System.out.println(vehicle + "在水里游");
	}
}

public class Main {
	public static void main(String[] args) {
		Vehicle2 Vehicle = new Vehicle2();
		Vehicle.run("摩托车");
		Vehicle.run("汽车");
		Vehicle.runAir("飞机");
		Vehicle.runWater("轮船");
	}
}

改进的分析:
1.这种修改方法没有对原来的类做大的修改,只是增加方法;
2.增加的部分不影响原有部分,降低了变更引起的风险;
3.这里在类这个级别上没有遵守单一职责原则,但是在方法级别上,仍然是遵守单一职责。
二、开放-封闭原则(面向对象设计的最终目标)
一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。
原例:

class Rectangle {
	void draw() {
		System.out.println("矩形");
	}
}

class Circle {
	void draw() {
		System.out.println("圆形");
	}
}

class Triangle { // 新增三角形——肯定要改
	void draw() {
		System.out.println("三角形");
	}
}

class GraphicDraw {
	void drawgraph(int type) {
		if (type == 1) {
			Rectangle rec = new Rectangle();
			rec.draw();
		} else if (type == 2) {
			Circle c = new Circle();
			c.draw();
		} else if (type == 3) { // 新增绘制三角形
			Triangle t = new Triangle();
			t.draw();
		}
	}
}

public class Main {
	public static void main(String[] args) {
		GraphicDraw graphicdraw = new GraphicDraw();
		graphicdraw.drawgraph(2); // 客户端肯定要改
	}
}

原例的分析:
1.优点是比较好理解,简单易操作。
2.缺点是违反了开闭原则(对扩展(提供方)开放,对修(使用方)关闭):需要给类增加新功能的时候,尽量不要修改代码,或者尽可能少修改代码。
3.本例,需要新增一个图形种类时,修改的地方比较多。
改进:

abstract class Shape {
	public abstract void draw(); // 抽象方法
}

class GraphicDraw { // 新增绘制图形不需修改此类
	void drawgraph(Shape s) {
		s.draw();
	}
}

class Rectangle extends Shape {
	public void draw() {
		System.out.println("矩形");
	}
}

class Circle extends Shape {
	public void draw() {
		System.out.println("圆形");
	}
}

class Triangle extends Shape { // 新增三角形
	public void draw() {
		System.out.println("三角形");
	}
}

public class Main {
	public static void main(String[] args) {
		GraphicDraw graphicdraw = new GraphicDraw();
		graphicdraw.drawgraph(new Circle());
		graphicdraw.drawgraph(new Rectangle());
		graphicdraw.drawgraph(new Triangle());
	}
}

改进分析:
1.Rectangle和Circle有共同的draw方法,创建抽象Shape类做成基类,并提供抽象的draw方法,让子类去实现,当需要新的图形时,只需要让新的图形继承Shape,并实现draw方法。
2.画图类GraphicDraw不出现具体的类,用抽象类Shape。这样使用方的代码就不需要修改,满足开闭原则。
三.里氏代换原则
子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。
原例:

class A {
	public int func1(int num1, int num2) {
		return num1 - num2;
	}
}

class B extends A {
	public int func1(int a, int b) {
		return a + b;
	}

	public int func2(int a, int b) {
		return func1(a, b) + 9;
	}
}

public class Main {

	public static void main(String[] args) {
		A a = new A();
		System.out.println("11-3=" + a.func1(11, 3));
		System.out.println("1-8=" + a.func1(1, 8));
		System.out.println("-------");
		B b = new B();
		System.out.println("11-3=" + b.func1(11, 3));
		// 这里本意是求出11-3
		System.out.println("1-8=" + b.func1(1, 8));
		System.out.println("11+3+9=" + b.func2(11, 3));
	}
}

原例分析:
原来运行正常的相减功能发生了错误。原因就是类B重写了父类的方法func1,造成原有功能出现错误。
改进:

//创建-个更加基础的基类
class Base {
//把更加基础的方法和成员写到Base类
}

//A类
class A extends Base {
//返回两个数的差
	public int func1(int num1, int num2) {
		return num1 - num2;
	}
}

class B extends Base {
	A a = new A();

	public int func1(int a, int b) {
		return a + b;
	}

	public int func2(int a, int b) {
		return func1(a, b) + 9;
	}

	public int func3(int a, int b) {
		return this.a.func1(a, b);
	}
}

public class Main {
	public static void main(String[] args) {
		A a = new A();
		System.out.println("11-3=" + a.func1(11, 3));
		System.out.println("1-8=" + a.func1(1, 8));
		System.out.println("-------");
		B b = new B();
		// 因为B类不再继承A类,因此调用者,不会再func1是求减法
		// 调用完成的功能就会很明确
		System.out.println("11+3=" + b.func1(11, 3));// 这里本意是求出11+3
		System.out.println("1+8=" + b.func1(1, 8));// 1+8
		System.out.println("11+3+9=" + b.func2(11, 3));
		// 使用组合仍然可以使用到A类相关方法
		System.out.println("11-3=" + b.func3(11, 3));// 这里本意是求出11-3
	}
}

四.依赖倒转原则
1)高层模块不应该依赖低层模块,二者都应该依赖其抽象。
2)抽象不应该依赖细节,细节应该依赖抽象。
3)依赖倒转(倒置)的中心思想是面向接口编程。
原例:

public class Main {
	public static void main(String[] args) {
		Person person = new Person();
		person.receive(new Email());
	}
}

class Email {
	public String getInfo() {
		return "电子邮件信息: hello world ";
	}
}

/*
 * Person 类 接受消息,将Email类 作为参数 产生了依赖 如果 参数发生变化,即接受的是微信 或短信 整个方法需要改动
 */
class Person {
	public void receive(Email email) {
		System.out.println(email.getInfo());
	}
}

原例分析:
1.简单,比较容易想到
2.如果我们获取的对象是微信,短信等,则新增类,同时Perons也要增加相应的接收方法。
3.解决:引入一个抽象的接口IReceiver,表示接收者,这样Person类与接口IReceiver发生依赖因为Emai1, WeiXin等属于接收的范围,它们各自实现IReceiver接口,这样就符合依赖倒转原则。
改进:

/*定义接受的接口 */
interface IReciver {
	public String getInfo();
}

class Email implements IReciver {
	public String getInfo() {
		return "电子邮件信息: hello world ";
	}
}

class WenXin implements IReciver {
	public String getInfo() {
		return "微信信息: hello WenXin ";
	}
}

/* Person 类 接受消息 将IReciver 接口 作为参数 产生了依赖 */
class Person {
	public void receive(IReciver reciver) {
		System.out.println(reciver.getInfo());
	}
}

public class Main {
	public static void main(String[] args) {
		Person person = new Person();
		person.receive(new Email());
//传入不同实现类 实现不同的接受
		person.receive(new WenXin());
	}
}

五.合成/聚合复用原则
尽量使用合成/聚合,不要使用类继承达到复用的目的。
如果有类A和类B,类B有方法opertion1()、 opertion2() 和opertion3(),类A需要用类B的方法opertion2() ,如何做?

1(依赖):
class B{
opertion (A a) {
a. opertion2() ; }
}2(聚合):
class B{
A a;
void setA (A a){
a. opertion2() ;} }3(组合):
class B{
A a=new A( );
}

六.接口隔离原则
使用多个专门的接口比使用单一的总接口要好。换而言之,
接口尽量细化,接口中的方法尽量少。
场景:
1.类B实现接口Interface1 ,类A通过接口Interface1依赖(使 用)类B,但是只会用到1,2,3方法。
2.类D实现接口Interface1 ,类C通过接口Interface1依赖(使 用)类D,但是只会用到1,4,5方法。
原例:

interface Interface1 {
	void operation1();

	void operation2();

	void operation3();

	void operation4();

	void operation5();
}

class B implements Interface1 {
public void operation1() {System. out.println("B实现了operation1"); }

public void operation2() {System. out.println("B实现了operation2"); }

public void operation3() {System. out.println("B实现了operation3"); }

public void operation4() {System. out.println("B实现了operation4" ); }

public void operation5() {System. out.println("B实现了operation5"); } }
//类D实现接口Interface1 
class D implements Interface1 {
public void operation1() {System. out.println("D实现了operation1"); }
public void operation2() {System. out.println("D实现了operation2"); }
public void operation3() {System. out.println("D实现了operation3"); }
public void operation4() {System. out.println("D实现了operation4" ); }
public void operation5() {System. out.println("D实现了operation5"); } }
//类A通过接口Interface1依赖(使用) 类B,但是只会用到1,2,3方法
class A{
public void depend1(Interface1 i) {
i.operation1();
}
public void depend2(Interface1 i) {
i.operation2();
}
public void depend3(Interface1 i) {
i.operation3();}
}
//类C通过接口Interface1依赖(使用) 类D,但是只会用到1,4,5方法
class C{
public void depend1(Interface1 i) {
i.operation1();
}
public void depend4(Interface1 i) {
i.operation4();
}
public void depend5(Interface1 i) {
i.operation5();}
}
public class Main {
public static void main(String[] args) {
A a=new A();
C c=new C();
//类A 通过接口 依赖类B
a.depend1(new B());
a.depend2(new B());
a.depend3(new B());
//类C 通过接口 依赖类D
c.depend1(new D());
c.depend4(new D());
c.depend5(new D());
} }

原例分析:
类A通过接口Interface1依赖类B,类C通过接口Interface1依赖类D,而接口 Interface1对于类A和类C来说不是最小接口,类B和类D必须去实现它们不需要的方法。
改进:

interface Interface1 {
	void operation1();
}

interface Interface2 {
	void operation2();

	void operation3();
}

interface Interface3 {
	void operation4();

	void operation5();
}

//类B 实现接口Interface1 ,Interface2的所有方法
class B implements Interface1,Interface2 {
public void operation1() {
System.out.println("B 实现 operation1");
}
public void operation2() {
System.out.println("B 实现 operation2");
}
public void operation3() {
System.out.println("B 实现 operation3");
} }
//类A 通过接口 Interface1,Interface2 依赖 (使用)类B 只会用到方法1,2,3

class A {
	public void depend1(Interface1 i) {
		i.operation1();
	}

	public void depend2(Interface2 i) {
		i.operation2();
	}

	public void depend3(Interface2 i) {
		i.operation3();
	}
}

//类D实现接口Interface1,Interface3 的所有方法
class D implements Interface1, Interface3 {
	public void operation1() {
		System.out.println("D 实现 operation1");
	}

	public void operation4() {
		System.out.println("D 实现 operation4");
	}

	public void operation5() {
		System.out.println("D 实现 operation5");
	}
}
//类C 通过接口 Interface1,Interface3 依赖 (使用)类D 只会用到方法1,4,5

class C {
public void depend1(Interface1 i) {
i.operation1();
}
public void depend4(Interface3 i) {
i.operation4();
}
public void depend5(Interface3 i) {
i.operation5();
} }
public class Main {
public static void main(String[] args) {
A a=new A();
C c=new C();
//类A 通过接口 依赖类B
a.depend1(new B());
a.depend2(new B());
a.depend3(new B());
//类C 通过接口 依赖类D
c.depend1(new D());
c.depend4(new D());
c.depend5(new D());
} }

改进分析:
接口Interface1拆分为独立的几个接口,类A和类C分别与它们需要的接口建立依赖关系。也就是采用接口隔离原则。接口Interface1 中出现的方法,根据实际情况拆分为三个接口。
七.迪米特法则(最少原则)
对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的public方法,不泄露任何信息。即至于直接朋友通信。
原例:

import java.util.ArrayList;
import java.util.List;

//学校总部员工类
class Employee {
    private String id;

    public void setId(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }
}

//学院的员工类
class CollegeEmployee{
    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

//管理学院员工的管理类
class CollegeManager{
    public List<CollegeEmployee> getAllEmployee(){
        List<CollegeEmployee> list = new ArrayList();
        for(int i = 0; i < 10; i++) {
          CollegeEmployee emp = new CollegeEmployee();
          emp.setId("学院员工 id = " + i);
          list.add(emp);
        }
        return list;
    }
}

//学校管理类
//分析SchoolMangager 类的直接朋友有哪些Employee,CollegeManager
//CollegeEmployee 不是直接朋友而是一个陌生类,这样违背了迪米特法则
class SchoolManager{
    public List<Employee> getAllEmployee(){
        List<Employee> list = new ArrayList();
        for(int i = 0; i < 5; i++) {
          Employee emp = new Employee();
          emp.setId("学校总部的员工id = " + i);
          list.add(emp);
        }
        return list;
    }


    //该方法完成输出学校总部和学院员工信息(id)
    void printAllEmployee(CollegeManager sub){
            //获取到学院员工
        List<CollegeEmployee> list1 = sub.getAllEmployee();
        System.out.println("-------学院员工---------");
        for (CollegeEmployee employee : list1) {
            System.out.println(employee.getId());
        }


        //获取到学校总部的员工
        List<Employee> list2 = this.getAllEmployee();
        System.out.println("-------学校总部员工---------");
        for (Employee employee : list2) {
            System.out.println(employee.getId());
        }
    }
}

public class Main {
    public static void main(String[] args) {
        //创建了一个SchoolManager对象
        SchoolManager schoolManager = new SchoolManager();

        //输出学院的员工id 和 学校总部的员工信息
        schoolManager.printAllEmployee(new CollegeManager());
    }
}

原例分析:

  1. 这里的CollegeEmployee不是 SchoolManager的直接朋友
  2. CollegeEmployee 是以局部变量方式出现在SchoolManager
  3. 违反了迪米特法则

改进:

import java.util.ArrayList;
import java.util.List;
//学校总部员工类
class Employee {
    private String id;

    public void setId(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }
}

//学院的员工类
class CollegeEmployee{
    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

//管理学院员工的管理类
class CollegeManager{
    public List<CollegeEmployee> getAllEmployee(){
        List<CollegeEmployee> list = new ArrayList();
        for(int i = 0; i < 10; i++) {
          CollegeEmployee emp = new CollegeEmployee();
          emp.setId("学院员工 id = " + i);
          list.add(emp);
        }
        return list;
    }
    
    
    void printEmployee(){
        List<CollegeEmployee> list1 = getAllEmployee();
        System.out.println("-------学院员工---------");
        for (CollegeEmployee employee : list1) {
            System.out.println(employee.getId());
        }
    }
}

//学校管理类
//分析SchoolMangager 类的直接朋友有哪些Employee,CollegeManager
//CollegeEmployee 不是直接朋友而是一个陌生类,这样违背了迪米特法则
class SchoolManager{
    public List<Employee> getAllEmployee(){
        List<Employee> list = new ArrayList();
        for(int i = 0; i < 5; i++) {
          Employee emp = new Employee();
          emp.setId("学校总部的员工id = " + i);
          list.add(emp);
        }
        return list;
    }


    //该方法完成输出学校总部和学院员工信息(id)
    void printAllEmployee(CollegeManager sub){
        //分析问题
        //1. 将输出学院的员工方法,封装到CollegeManager
        sub.printEmployee();
        


        //获取到学校总部的员工
        List<Employee> list2 = this.getAllEmployee();
        System.out.println("-------学校总部员工---------");
        for (Employee employee : list2) {
            System.out.println(employee.getId());
        }
    }
}
public class Main {
    public static void main(String[] args) {
        //创建了一个SchoolManager对象
        SchoolManager schoolManager = new SchoolManager();

        //输出学院的员工id 和 学校总部的员工信息
        schoolManager.printAllEmployee(new CollegeManager());
    }
}

由于每个类都减少了不必要的依赖,因此迪米特法则
只是要求降低类间(对象间)耦合关系, 并不是要求完
全没有依赖关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值