“单一职责” 模式
- 在软件组织的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任。
- 典型模式:
- Decorator
- Bridge
一、代码示例
**背景:**假设现在有一款游戏,我们要在手机品牌M和手机品牌N上都可以玩该游戏,那么很容易就有如下的实现思路:
interface BrandGame {
void run();
}
class BrandMGame implements Game {
@Override
public void run() {
System.out.println("M手机运行游戏");
}
}
class BrandNGame implements Game {
@Override
public void run() {
System.out.println("N手机运行游戏");
}
}
**需求变更一:**此时我们不仅要在手机中实现玩游戏的功能,还要实现通讯录的增删改查的功能,基于继承的思路,就会抽象出手机品牌基类,品牌M和品牌N继承自该类,M和N又有各自的子类,就有了下面的结构:
代码如下:
interface Brand {
void run();
}
abstract class BrandM implements Brand {
}
abstract class BrandN implements Brand {
}
class BrandMGame extends BrandM {
@Override
public void run() {
System.out.println("运行M品牌游戏");
}
}
class BrandNGame extends BrandN {
@Override
public void run() {
System.out.println("运行N品牌游戏");
}
}
class BrandMAddressList extends BrandM {
@Override
public void run() {
System.out.println("运行M品牌通信录");
}
}
class BrandNAddressList extends BrandN {
@Override
public void run() {
System.out.println("运行N品牌通信录");
}
}
**需求变更二:**我们要添加MP3音乐播放器的功能,并且要添加一个手机品牌Q。此时我们按照上面的思路,需要新加6个类。如果有n个功能,m个品牌,我们需要维护的类就是m * n个。
分析:这种架构违反了单一职责原则,即品牌和功能是两个变化的方向,我们如果将其耦合到一起,会导致类的个数急剧增加,但是每个累的基本功能又一样,从而导致在发生修改的时候变得难以维护。
**解决办法:**将手机品牌和功能分离开来,使用如下的结构:
interface Software {
void run();
}
class Game implements Software {
@Override
public void run() {
System.out.println("运行游戏");
}
}
class AddressList implements Software {
@Override
public void run() {
System.out.println("运行通信录");
}
}
abstract class Brand {
protected Software software;
public void setSoftware(Software software) {
this.software = software;
}
public abstract void run();
}
class BrandM extends Brand {
@Override
public void run() {
System.out.println("M品牌手机运行软件");
software.run();
}
}
class BrandN extends Brand {
@Override
public void run() {
System.out.println("N品牌手机运行软件");
software.run();
}
}
在客户端调用的代码:
//客户端调用代码
class Client {
public static void main(String[] args) {
Software software;
software = new Game();
Brand bM = new BrandM();
bM.setSoftware(software);
bM.run();
Brand bN = new BrandN();
bN.setSoftware(software);
bN.run();
}
}
之后如果需要添加新的手机品牌或者新的功能,我们只需要添加两个类即可。
二、动机
由于某些类型的固有实现逻辑,导致它们具有两个甚至多个变化的维度,多个变化的维度将使代码变得很难维护。
三、定义
将抽象部分与实现部分分离,使它们都可以独立地变化。
即:实现系统可能有多角度的分类,每一种分类都有可能变化,那么就把这种多角度分离出来让它们独立变化,减少它们之间的耦合。