设计模式作业 — 4

依赖倒转原则

依赖倒转原则(DependenceInversionPrinciple)是指:
1)高层模块不应该依赖低层模块,二者都应该依赖其抽象
2)抽象不应该依赖细节,细节应该依赖抽象
3)依赖倒转(倒置)的中心思想是面向接口编程
4)依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在Java中,抽象指的是接口或抽象类,细节就是具体的实现类。
5)使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
示例一、实现person接收消息方式1

package org.yunan.design;

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

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

class Person {
	public void receive(Email email) {
		System.out.println(email.getInfo());
	}
}

分析:
1.简单,比较容易想到
2.如果我们获取的对象是微信,短信等,则新增类,同时Perons也要增加相应的接收方法
3.Person 类接受消息,将Email类作为参数产生了依赖* 如果参数发生变化,即接受的是微信或短信整个方法需要改动

解决:定义接受的接口调用时传入不同的实现类实现不同的接受,引入一个抽象的接口IReceiver,表示接收者,这样Person类与接口IReceiver发生依赖因为Emai1,WeiXin等属于接收的范围,它们各自实现IReceiver接口,这样就符合依赖倒转原则。

package org.yunan.design;

public class DependecyInversion1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Person person = new Person();
		person.receive(new Email());// 传入不同实现类实现不同的接受
		person.receive(new WenXin());
		person.receive(new QQ());
	}

}
/*定义接受的接口*/
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";
	}
}
class QQ implements IReciver {

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

PS:
1)低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好。
2)变量的声明类型尽量是抽象类或接口,这样变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化。B obj=new A(); //B是抽象类,A继承B,如果要扩展A,则只要扩充B3)继承时遵循里氏替换原则。

合成/聚合复用原则

合成/聚合复用原则是:尽量使用合成/聚合的方式,而不是使用继承
合成/聚合复用原则来源:在面向对象的设计中,
1.如果直接继承基类,会破坏封装,因为继承将基类的实现细节暴露给子类;
2.如果基类的实现发生改变,则子类的实现也发生改变;
3.从基类继承而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性。
4.于是就提出了合成/聚合复用原则:尽量使用合成/聚合,不要使用类继承达到复用的目的。
设计原则核心思想:

  1. 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
  2. 针对接口编程,而不是针对实现编程。
  3. 为了交互对象之间的松耦合设计

接口隔离原则

基本介绍:不应该依赖不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上。
示例一:
类B实现接口Interface1 ,类A通过接口Interface1依赖(使用)类B,但是只会用到1,2,3.
类D实现接口Interface1 ,类C通过接口Interface1依赖(使用)类D,但是只会用到1,4,5方法

package org.yunan.design;

public class segregation {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		A a=new A();
		C c=new C();
		a.depend1(new B());
		a.depend2(new B());
		a.depend3(new B());
	    c.depend1(new D());
		c.depend4(new D());
		c.depend5(new D());
	}

}

interface Interface1 {
	void operation1();

	void operation2();

	void operation3();

	void operation4();

	void operation5();
}

//类B实现接口Interface1 class 
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");
	}
}

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");
	}
}

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

	public void depend4(Interface1 i) {
		i.operation4();
	}

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

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

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

分析:类B、D中有大量多余的方法没有利用,资源浪费严重
类A通过接口Interface1依赖类B,
1.类C通过接口Interface1依赖类D,
2.如果接口Interface1对于类A和类C来说不是最小接口,那么类B和类D必须去实现它们不需要的方法。
3.如上代码违背了接口隔离原则(不应该依赖不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上)类A不需要用到类B4,5方法类C不需要用到类D2,3方法

解决:
将接口Interface1拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。

package org.yunan.design;

public class segregation1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		A a=new A();
		C c=new C();
		a.depend1(new B());
		a.depend2(new B());
		a.depend3(new B());
	    c.depend1(new D());
		c.depend4(new D());
		c.depend5(new D());
	}

}

interface Interface1 {
	void operation1();
}

interface Interface2 {
	void operation2();

	void operation3();
}

interface Interface3 {
	void operation4();

	void operation5();
}

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");
	}
}

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

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

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

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");
	}
}

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

	public void depend4(Interface3 i) {
		i.operation4();
	}

	public void depend5(Interface3 i) {
		i.operation5();
	}
}

接口隔离原则:
使用多个专门的接口比使用单一的总接口要好。换而言之,接口尽量细化,接口中的方法尽量少。
1.过于臃肿的接口是对接口的污染。不应该强迫依赖于它们不用的方法:
2.类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类C来说不是最小接口,而类B和类D必须去实现它们不需要的方法。

迪米特法则

基本介绍:
1)一个对象应该对其他对象保持最少的了解
2)类与类关系越密切,耦合度越大
3)迪米特法则(Demeter Principle)又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的public方法,不泄露任何信息。
4)迪米特法则还有个更简单的定义:只与直接的朋友通信
5)直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。

class A{
B objb;  //成员变量中的类
Bmethoda(C para);//方法参数中的类
CD methoda(); //方法返回值中的类D
}//类B,C,D是类A的直接朋友
class C{
methodc(){E para =new E;}//类E出现在局部变量中
 } //类E不是类C的直接朋友

实例1:
有一个学校,下属有各个学院和总部,现要求打印出学校总部员工ID和学院员工的id。编程实现上面的功能。

package org.yunan.design;
import java.util.ArrayList;
import java.util.List;

public class Demeter {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		 //创建了一个SchoolManager对象
        SchoolManager schoolManager = new SchoolManager();

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

	}

}

//学校总部员工类
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){
        //分析问题
        //1. 这里的CollegeEmployee不是 SchoolManager的直接朋友
        //2. CollegeEmployee 是以局部变量方式出现在SchoolManager
        //3. 违反了迪米特法则

        //获取到学院员工
        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());
        }
    }
}

改进:

package org.yunan.design;
import java.util.ArrayList;
import java.util.List;

public class Demeter1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		  //创建了一个SchoolManager对象
	      SchoolManager schoolManager = new SchoolManager();

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

	}

}
//学校总部员工类
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 < 5; 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());
      }
  }
}

迪米特法则(Law of Demeter,简写LoD)又叫做最少知识原则(Least Knowledge Principle或简写为LKP)
1.如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
2.也就是说,一个对象应当对其它对象有尽可能少的了解。
其它表述
3.一个模块设计的好坏的一个重要标志就是该模块在多大程度上将自己的内部数据与实现的有关细节隐藏起来。
4.一个软件实体应当尽可能少的与其他实体发生相互作用。
5.每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
PS:
迪米特法则的目的在于降低类与类之间的耦合。由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,使得相互间存在尽可能少的依赖关系。信息的隐藏促进了软件的复用。
但是注意:由于每个类都减少了不必要的依赖,因此迪米特法则只是要求降低类间(对象间)耦合关系,并不是要求完全没有依赖关系。

以上部分摘取自朱红梅老师2020年5月的课件。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java软件设计模式作业是一门涉及面广、技术难度较高的课程。在这门课程中,学生需要学习并掌握软件设计中常用的设计模式,如工厂模式、单例模式、观察者模式等。通过对设计模式的理解与应用,学生可以提高软件的可维护性、可扩展性和可重用性。 在大作业中,学生需要根据所学的设计模式,选择一个具体的软件项目进行设计与实现。可以选择一个真实的项目,或者自行构思一个虚拟的项目。学生需要根据项目需求,使用适当的设计模式进行系统的构建与实现。 大作业的要求包括以下几个方面: 1. 系统的需求分析与设计:学生需要深入理解项目需求,进行系统的分析与设计。根据需求,选择与之匹配的设计模式,并合理地组织系统的结构与模块。 2. 设计模式的应用:学生需要在设计与实现过程中主动运用所学的设计模式,解决具体问题,提高系统的可维护性与可扩展性。学生需要灵活运用设计模式,不拘泥于一种模式的使用。 3. 代码质量与可读性:学生需要编写高质量的代码,并注重代码的可读性和规范性。代码应符合Java编程规范,并且能够清晰地表达设计思想和逻辑。 4. 功能完善与测试:学生需要实现项目的核心功能,对系统进行充分的测试,确保系统的可靠性和稳定性。 5. 文档撰写与演示:学生需要编写项目的设计文档、实现文档,清晰地描述系统的设计思路和实现过程。同时,需要进行项目的演示,并对设计与实现进行解释和总结。 通过完成Java软件设计模式作业,学生可以全面掌握设计模式的应用,提高软件设计与开发能力,为将来的工作和学习打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yu_Nan___

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值