Java设计模式(3:接口隔离原则和迪米特法则详解)
一、接口隔离原则
使用多个接口,而不使用单一的接口,客户端不应该依赖它不需要的接口。尽量的细化接口的职责,降低类的耦合度。
我们先来看一个例子:
小明家附近新开了一家动物园,里面有老虎、鸟儿、长颈鹿.....周末在逛动物园的时候,小明突发奇想,想用一种方式记录一下这些动物的习性,于是他将老虎和鸟儿的习性结合了一下,写了下面这段代码:
动物行为
// 动物行为
public interface Animal {
// 吃
public void eat();
// 游泳
public void swim();
// 飞
public void fly();
}
老虎Tiger
// 老虎
public class Tiger implements Animal {
@Override
public void eat() {
System.out.println("老虎在吃鸡肉.....");
}
@Override
public void swim() {
System.out.println("老虎在游泳.....");
}
@Override
public void fly() {
System.out.println("老虎不能飞.....");
}
}
小鸟Brid
// 小鸟
public class Brid implements Animal {
@Override
public void eat() {
System.out.println("小鸟在吃虫子.....");
}
@Override
public void swim() {
System.out.println("小鸟不会游泳.....");
}
@Override
public void fly() {
System.out.println("小鸟正在飞.....");
}
}
写完上面的三段代码后,小明发现了问题:在
Animal接口的三个方法中,Tiger是不会飞的,所以fly()方法对于Tiger是没有用的;Bird是不会游泳的,所以swim()方法对于Bird是没有用的。这样一来,Brid类和Tiger类都会空置一个方法,对于代码的结构设计来说不太合理。于是,他划掉了上面的三段代码,仔细思索了一会儿,写出了下面这几段代码:
// 游泳
public interface ISwim {
public void swim();
}
// 吃
public interface IEat {
public void eat();
}
// 飞
public interface IFly {
public void fly();
}
小鸟Bird
// 小鸟
public class Brid implements IEat,IFly {
@Override
public void eat() {
System.out.println("小鸟在吃虫子.....");
}
@Override
public void fly() {
System.out.println("小鸟正在飞.....");
}
}
老虎Tiger
// 老虎
public class Tiger implements IEat,ISwim {
@Override
public void eat() {
System.out.println("老虎在吃鸡肉.....");
}
@Override
public void swim() {
System.out.println("老虎在游泳.....");
}
}
这样来看,将
eat、swim、fly三种方法拆分开来,分别放在三个不同的接口里,这样动物拥有哪几种习性就实现哪几个接口,不会再用空置的方法存在,这样看起来也简洁明了,来看看类图:

二、迪米特法则
又被成为最少知道原则,指的是一个对象应该对其他对象保持最少的了解。一个实体类应当尽量少地和其他实体之间发生相互作用,使得系统模块相互独立。形象来说就是:只和朋友交流,不和陌生人说话。
迪米特法则认为,一个对象或方法,它只能够调用以下对象:
- 该对象本身
- 作为参数传进来的对象
- 在方法内创建的对象
我们先来模拟一个超市购物的场景:顾客Customer到收银台结账,收银员PaperBoy负责收钱。
顾客的钱包Wallet
// 钱包
public class Wallet {
// 钱包里装的钱
private Float value;
// 构造器
public Wallet(Float value) {
this.value = value;
}
// 获得钱包里的钱的金额
public Float getMoney(){
return this.value;
}
// 付账时 减钱
public void reduceMoney(Float money){
this.value -= money;
}
}
顾客Customer
// 顾客
public class Customer {
private Wallet wallet = new Wallet(50f);
public Wallet getWallet() {
return wallet;
}
}
收银员PaperBoy
// 收银员
public class PaperBoy {
// 收银员收钱
public void charge(Customer customer,Float money){
Wallet wallet = customer.getWallet();
if (wallet.getMoney() >= money){
System.out.println("顾客付账:" + money +"元");
// 减去 应付的钱
wallet.reduceMoney(money);
System.out.println("钱包里还剩:"+wallet.getMoney()+"元");
} else {
System.out.println("钱包里的金额不够......");
}
}
}
测试、运行
// 测试
public static void main(String[] args) {
PaperBoy paperBoy = new PaperBoy();
Customer customer = new Customer();
paperBoy.charge(customer,20f);
}

从测试代码和运行的结果来看,好像并没有什么问题。让我们来看一下类图:

从类图中我们发现:PaperBoy类与Wallet类有着千丝万缕的关系,顾客(Customer)的钱包(Wallet)好像并不是自己来控制的,而是由收银员(PaperBoy)来决定的,就连钱包(Wallet)里面的钱够不够也是由收银员(PaperBoy)来判断的;相当于顾客(Customer)将自己的钱包(Wallet)暴露给了收银(PaperBoy),这样来看,问题就很严重了,顾客(Customer)的隐私受到了侵犯,说大点就是民事纠纷,是可以上法庭的,可以通过法律追究责任的。所以我们思考良久,将上述代码改成下面这般:
钱包Wallet类不变,顾客Customer去掉给出钱包的getWallet()方法,增加付钱的pay()方法:
// 顾客
public class Customer {
private Wallet wallet = new Wallet(50f);
// 顾客自己付钱
public void pay(Float money){
if (wallet.getMoney() >= money){
System.out.println("顾客付账:" + money +"元");
// 减去 应付的钱
wallet.reduceMoney(money);
System.out.println("钱包里还剩:"+wallet.getMoney()+"元");
} else {
System.out.println("钱包里的金额不够......");
}
}
}
收银员PaperBoy类中的charge()方法中的代码删除原有的逻辑,改为调用顾客Customer类中的付钱pay()方法:
// 收银员
public class PaperBoy {
// 收银员收钱
public void charge(Customer customer,Float money){
customer.pay(money);
}
}
测试代码不变,我们再来看看类图:

从类的结构图来看:收银员PaperBoy只和顾客Customer有联系,钱包Wallet只和顾客Customer有联系。再此情况下,如果把钱包Wallet也当作一个人来看的话,这个就是如下的关系:
- 顾客
Customer和钱包Wallet是朋友 - 顾客
Customer和收银员PaperBoy是朋友 - 钱包
Wallet和收银员PaperBoy是陌生人
这个就符合我们所说的迪米特法则中的核心:只和朋友交流,不和陌生人说话。
Java设计模式(3:接口隔离原则和迪米特法则详解)的更多相关文章
- 设计模式之接口隔离原则(ISP)
一.定义: ISP:Interface Segregation Principle 接口隔离原则表明客户端不应该被强迫实现一些他们不会使用的接口,应该把胖接口中的方法分组,然后用多个接口代替它,每个接 ...
- IOS设计模式的六大设计原则之迪米特法则(LOD,Law Of Demeter)
定义 狭义的迪米特法则定义:也叫最少知识原则(LKP,Least Knowledge Principle).如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用.如果其中的一个类需要调用 ...
- 想真正了解JAVA设计模式看着一篇就够了。 详解+代码实例
Java 设计模式 设计模式是对大家实际工作中写的各种代码进行高层次抽象的总结 设计模式分为 23 种经典的模式,根据用途我们又可以分为三大类.分别是创建型模式.结构型模式和行为型模式 列举几种设 ...
- 设计模式 第一天 UML图,设计模式原则:开闭原则、依赖倒转原则、接口隔离原则、合成复用原则、迪米特法则,简单工厂模式
1 课程大纲 2 UML的概述 总结: UML unified model language 统一建模语言 一共有十种图: 类图 用例图 时序图 * 对象图 包图 组件图 部署图 协作图 状态图 (最 ...
- java设计模式学习笔记--接口隔离原则
接口隔离原则简述 客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应建立在最小的接口上 应用场景 如下UML图 类A通过接口Interface1依赖类B,类C通过接口Interface1依赖类 ...
- [设计模式]<<设计模式之禅>>关于接口隔离原则
在讲接口隔离原则之前,先明确一下我们的主角——接口.接口分为两种: ● 实例接口(Object Interface),在Java中声明一个类,然后用new关键字产生一个实例,它是对一个类型的事物的描述 ...
- ZT 设计模式六大原则(4):接口隔离原则
设计模式六大原则(4):接口隔离原则 分类: 设计模式 2012-02-27 08:32 17948人阅读 评论(21) 收藏 举报 设计模式classinterfacecstring框架 定义:客户 ...
- C#软件设计——小话设计模式原则之:接口隔离原则ISP
前言:有朋友问我,设计模式原则这些东西在园子里都讨论烂了,一搜一大把的资料,还花这么大力气去整这个干嘛.博主不得不承认,园子里确实很多这方面的文章,并且不乏出色的博文.博主的想法是,既然要完善知识体系 ...
- 设计模式之六大原则——接口隔离原则(ISP)
设计模式之六大原则——接口隔离原则(ISP) 转载于:http://www.cnblogs.com/muzongyan/archive/2010/08/04/1792528.html 接口隔离原则 ...
随机推荐
- 网站指纹识别工具Whatweb的使用
目录 whatweb 一些常见的Whatweb的扫描 常规扫描 批量扫描 详细回显扫描 扫描强度等级控制 快速本地扫描(扫描内网的主机) 将扫描结果导出至文件内 whatweb whatweb 是ka ...
- SSH后门万能密码
当我们在获得一台Linux服务器的 root 权限后,我们第一想做的就是如何维持这个权限,维持权限肯定想到的就是在目标服务器留下一个后门.但是留普通后门,肯定很容易被发现.我们今天要讲的就是留一个SS ...
- React-组合模式
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title&g ...
- unity怎么把工程打包成unitypackage文件
unity怎么把工程打包成unitypackage文件 想探讨问题的原因 上课的时候,看到老师的磁盘都要爆满了,主要的原因是同学们提交的2DGameKit,工程文件太大了. 文件没有压缩,占用空间是2 ...
- 【java--反射】注解(反射解析注解+注解应用)
创建实体类 package cn.com.codingce.iocannotation; /** * @Author: Jiangjun * @Date: 2019/10/7 9:54 */ publ ...
- Django(13)django时区问题
前言 我们都知道时区,标准时区是UTC时区,django默认使用的就是UTC时区,所以我们存储在数据库中的时间是UTC的时间,但是当我们做的网站只面向国内用户,或者只是提供内部平台使用,我们希望存储在 ...
- 用户对象/GDI对象/内核对象
对象的分类 Windows的对象可以分为三种,分别是用户对象,GDI对象和内核对象.系统使用用户对象支持窗口管理,使用GDI对象支持图形,并使用内核对象支持内存管理,进程执行和进程间通信(IPC) . ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十二)——istio+dapr构建多运行时服务网格
多运行时是一个非常新的概念.在 2020 年,Bilgin Ibryam 提出了 Multi-Runtime(多运行时)的理念,对基于 Sidecar 模式的各种产品形态进行了实践总结和理论升华.那到 ...
- [刷题] PTA 查验身份证
题目: 7-63 查验身份证 (15 分) 一个合法的身份证号码由17位地区.日期编号和顺序编号加1位校验码组成.校验码的计算规则如下: 首先对前17位数字加权求和,权重分配为:{7,9,10,5, ...
- [刷题] 454 4Sum II
要求 给出四个整型数组ABCD,寻找有多少 i j k l 的组合,使得A[i]+B[j]+C[k]+D[l]=0 ABCD元素个数均为N,0<=N<=500 示例 输入: A = [ 1 ...