实验六 设计模式

简介: 里氏替换原则通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。合成/聚合复用:将已有的对象纳入新对象中,使之成为新对象的一部分,因此新对象可以调用已有对象的功能。迪米特法则:只与你直接的朋友通信;不要跟"陌生人"说话;每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。接口隔离原则:第一种解释是客户端不应该依赖那些它不需要的接口。

@[Toc]

一、实验目的

(1)理解面向对象设计原则的基本概念

(2)掌握主要设计原则的概念、实现方法和实例

二、实验内容1

1.问题描述

​ 里氏代换原则

2.软件设计

修改之前:
在这里插入图片描述

修改之后:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hxLdV6rf-1663237151285)(C:/Users/86158/AppData/Local/Temp/ksohtml17104/wps11.jpg)]

3.程序实现代码

interface Conic{

public long getMajor_axis();

public long getShort_axis();

}

 

class Ellipse implements Conic{

private long major_axis ;

private long short_axis ;

public void setMajor_axis(long major_axis){

this.major_axis = major_axis ;

}

public long getMajor_axis(){

return this.major_axis;

}

public void setShort_axis(long short_axis){

this.short_axis = short_axis ;

}

public long getShort_axis(){

return this.short_axis;

}

}

 

class Circle implements Conic{

private long radius;

public void setRadius(long radius){

this.radius = radius;

}

public long getRadius(){

return radius;

}

public long getMajor_axis(){

return getRadius ();

}

public long getShort_axis(){

return getRadius();

}

}

4.测试及运行结果

未修改之前,在“圆形类是否是椭圆形类的子类”问题上是违法“里氏代换原则”的,修改之后,里氏代换原则没有没破坏。

里氏替换原则通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。

三、实验内容2

1.问题描述

合成/聚合复用原则:

继承的优点:实现、修改、拓展比较容易。

继承的缺点:1、运行时不可改变。2、破坏父类的包装性。3、父类改变子类随着改变。4、当不适应问题的时候,有可能需要改变父类。

2.软件设计

修改之前:

image-20220915180826311

修改之后:

image-20220915180835834

3.程序实现代码

public class People {

  Role role = new Role();

}

public class Emplyee extends Role{

}

public class Manager extends Role{

}

public class Role {

}

public class Student extends Role{

}

4.测试及运行结果

修改之前的设计Employee、Manager、Student分别描述一种角色,但是人可以有几种不同的角色,所以当一个类是另一个类的角色时,不应当使用继承描述这种关系。这一错误的设计源于把角色的等级结构与人的等级结构混淆起来,把Has-A误解为Is-A。这里采用合成/聚合关系的办法解决这个问题,增加一个Role角色,People和Role是合成关系,Role类和Employee类、Manager类、Student类之间是继承关系。

四、实验内容3

1.问题描述

依赖倒转原则

2.软件设计

image-20220915180758476

3.程序实现代码

class Account{

  private AccountType accountType;

  private AccountStatus accountStatus;

  public Account(AccountType acctType){

   //……

  }

  public void deposit(float amount){

   //……

}

}

 

abstract class AccountType{

public abstract void deposit(float amount);

}

abstract class AccountStatus{

public abstract void sendMessage();

}

 

class Savings extends AccountType{

public void deposit(float amount){

   //……

}

}

class Settlement extends AccountType{

public void deposit(float amount){

   //……

}

}

 

class Open extends AccountStatus{

public void sendMessage(){

   //……

}

}

class Frozen extends AccountStatus{

public void sendMessage(){

   //……

}

}

4.测试及运行结果

实现类只实现接口和抽象类声明的方法,不能增加新的方法。

Account类依赖于AccountType类和AccountStatus两个抽象类,而不是它们的子类型。Account类不依赖于具体类,因此当有新的具体类型添加到系统中时,Account类不需要改变。减少了类之间的耦合性,提高系统的可维护性,减少并行开发引起的风险,提高代码的可读性。

五、 实验内容

1.问题描述

迪米特法则

2.软件设计

修改之前

img

修改之后

img

3.程序实现代码

public class Agent {

  private Outside_world ow = new Outside_world();

  public void forward(){

​    ow.operation2();

  }

}

public class Outside_world {

  public void operation2()

  {

 

  }

}

public class Star {

  public void operation1(Agent agent){

​    agent.forward();

  }

}

4.测试及运行结果

修改之前,明星类和外界类发生了相互作用,不满足迪米特法则。

改造的方法是调用转发,Star无须知道Outside_word的存在就可以做同样的事情。

六、 实验内容5

1.问题描述

接口隔离法则

2.软件设计

修改之前

img

修改之后

img

3.程序实现代码

 interface Searcher{

  void search(String[] keyword);

  void getResultset();

 }

 

 interface Indexer{

  void reIndexAll();

  void updateIndex();

 }

 

 interface ResultSet{

  void first();                //将光标移到集合的第一个元素

  void last();                //将光标移到集合的最后一个元素

  void next();                //将光标移到集合的下一个元素

  void previous();            //将光标移到集合的前一个元素

  String getExcerpt();        //返回当前记录的摘要

  String getFullRecord();        //将记录的全文返回

 }

 

4.测试及运行结果

原来的代码违反了角色分割原则,原因是不同功能的接口放在一起,一个接口包含了搜索器角色、索引生成器角色以及搜索结果集角色多种角色。

接口隔离原则的第一种解释是客户端不应该依赖那些它不需要的接口。另一种解释是一旦一个接口太大,则需要将它分割成一些更细小的接口,使用该接口的客户端仅需要知道与之相关的方法即可。

七、 实验内容6

1.问题描述

通过仔细分析,设计人员发现该类图存在非常严重的问题,如果需要增加一种新的大小的笔或者增加一种新的颜色,都需要增加很多子类,如增加一种绿色,则对应每一种大小的笔都需要增加一支绿色笔,系统中类的个数急剧增加。

试根据依赖倒转原则和合成复用原则对该设计方案进行重构,使得增加新的大小的笔和增加新的颜色都较为方便。

2.软件设计

依赖倒转原则(子类只实现声明过的方法,实现类依赖抽象类或接口,构建出一个抽象)

img

合成/聚合复用(将已有对象,纳入新对象之中,新对象可以调用已有对象的方法,构建出一个新的对象)

img

八、 实验内容7

1.问题描述

结合面向对象设计原则分析:正方形是否是长方形的子类?

2.软件设计

不是,违反了里氏代换原则,例如有一个方法,如果长方形的短边小于等于长边,短边就加一,直到短边大于等于长边,这个方法对于长方形是适用的,但是对于正方形是不适用的,正方形类会一直执行这个方法直到溢出。所以它违反了理性代换原则中:引用父类的地方必须能透明地使用子类的对象。子类型必须能够替换掉它们的父类型;子类继承了父类,子类可以以父类的身份出现。

九、 实验内容8

1.问题描述

如果在上述系统中增加一个新的组件类,则必须修改与之交互的其他组件类的源代码,将导致多个类的源代码需要修改。

现根据迪米特法则对上述代码进行重构,以降低组件之间的耦合度。

2.软件设计

原图:

img

根据迪米特法则修改后的图:

img

总结

  • 里氏替换原则通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
  • 合成/聚合复用:将已有的对象纳入新对象中,使之成为新对象的一部分,因此新对象可以调用已有对象的功能。
  • 迪米特法则:只与你直接的朋友通信;不要跟"陌生人"说话;每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
  • 接口隔离原则:第一种解释是客户端不应该依赖那些它不需要的接口。另一种解释是一旦一个接口太大,则需要将它分割成一些更细小的接口,使用该接口的客户端仅需要知道与之相关的方法即可。
  • 依赖倒转原则:抽象不应当依赖于细节;细节应当依赖于抽象。依赖倒转原则还可以表达为要针对接口编程,不要针对实现编程。
相关文章
|
11月前
|
设计模式 算法
设计模式的分类
设计模式(design pattern)是对面向对象设计中反复出现的问题的解决方案。其并非是一种技术,而是在项目迭代的过程中,为了实现一些功能,设计了一些解决方案,将这些经验进行总结出来的一个模式体系,这个体系是总结的经验。
38 0
|
1月前
|
设计模式
设计模式:从理论到实际应用
【8月更文挑战第18天】设计模式是软件工程中解决特定问题的有效方案,提升代码质量并促进团队协作。本文从理论出发,探讨设计模式在实际项目中的应用。设计模式分为创建型、结构型和行为型,遵循如开闭原则等设计原则。通过工厂模式创建不同类型的电子签章,观察者模式实现在状态变更时的通知机制,以及建造者模式灵活组装复杂对象。以虚拟运营商平台为例,采用责任链模式优化审批流程,展示设计模式的实际价值。
|
4月前
|
设计模式 前端开发 安全
C++23种设计模式&软件设计模型
C++23种设计模式&软件设计模型
|
4月前
|
设计模式 开发者
【设计模式】设计模式综述
【1月更文挑战第12天】【设计模式】设计模式综述
|
10月前
|
设计模式
设计模式系列教程(03) - 设计模式分类及六大原则
设计模式系列教程(03) - 设计模式分类及六大原则
40 0
|
设计模式 SQL Java
为什么一定要学习设计模式
先来看一个生活案例,当我们开心时,也许会寻求享乐。在学习设计模式之前,你可能会这样感叹:
48 0
|
设计模式 算法
设计模式学习
设计模式学习
|
设计模式 算法
设计模式简单分类
设计模式简单分类
70 0
|
设计模式 开发框架 算法
【Java设计模式 设计模式与范式】设计模式概述、基本原则及分类
【Java设计模式 设计模式与范式】设计模式概述、基本原则及分类
64 0
|
设计模式 SQL 缓存
【设计模式】【第九章】【设计模式小结】
单一职责原则:一个类只负责一个功能领域中的相应职责 开闭原则:一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展