面向对象的设计原则之--单一职责原则

基本概念

单一职责原则(Single Responsibility Principle,SRP)

定义:应该有且仅有一个原因引起类的变更(There should never be more than one reason for a class to change)

优点:

  • 降低类的复杂度;
  • 提高类的可读性,因为类的职能单一,看起来比较有目的性
  • 提高系统的可维护性,降低变更程序引起的风险

具体代码演示

例如下面的工厂类,负责 将原料进行预处理然后加工成产品X和产品Y:

public class Factory {
    private String preProcess(String material){
        return "*"+material+"*";
    }
    public String processX(String material) {
        return preProcess(material) +"加工成:产品X";
    }
    public String processY(String material) {
        return preProcess(material) +"加工成:产品Y";
    }
}

现因市场需求,优化产品X的生产方案,需要改变原料预处理的方式,修改如下:

 private String preProcess(String material){
        return "#"+material+"#";
    }
public class Client {
  public static void main(String args[]) {
    Factory factory = new Factory();
    System.out.println(factory.processX("原料"));
    System.out.println(factory.processY("原料"));
  }
}

运行结果如下:

修改前:
*原料*加工成:产品X
*原料*加工成:产品Y
修改后:
#原料#加工成:产品X
#原料#加工成:产品Y

从运行结果中可以发现,在使产品X可以达到预期生产要求的同时,也导致了产品Y的变化,但是产品Y的变化并不在预期当中,这便导致程序运行错误甚至崩溃;

为了避免这种问题的发生,我们在软件开发中,应当注重各职责间的解耦和增强功能类的内聚性,来实现类的职责的单一性。

切断职责P1与职责P2之间的关联(解耦),然后将职责P1封装到功能类T1中,将职责P2封装到功能类T2中,使职责P1与职责P2分别由各自的独立的类来完成(内聚)。

按照单一职责原则可以将上面的工厂类按照以下方式进行分解:

定义一个抽象工厂类AFactory,有预加工preProcess和加工process方法:

public abstract class AFactory {
    protected abstract String preProcess(String material);
    public abstract String process(String material);
}

由工厂类FactoryX继承自AFactory,专门生产产品X:

public class FactoryX extends AFactory{

    @Override
    protected String preProcess(String material) {
        return "*"+material+"*";
    }
    @Override
    public String process(String material) {
        return preProcess(material) +"加工成:产品X";
    }
}

由工厂类FactoryY继承自AFactory,专门生产产品Y:

public class FactoryY extends AFactory{
    @Override
    protected String preProcess(String material) {
        return "*"+material+"*";
    }
    @Override
    public String process(String material) {
        return preProcess(material) +"加工成:产品Y";
    }
}

场景类中调用如下:

public class Client {
    public static void main(String args[]) {
        produce(new FactoryX());
        produce(new FactoryY());
    }
    private static void produce(AFactory factory) {
        System.out.println(factory.process("原料"));
    }
}

现在优化产品X的生产方案,像之前那样改变原料预处理的方式,只需要改变类FactoryX中preProcess方法即可;

例如下面的工厂类负责将原料多次加工处理后生产产品X:

public class Factory {
    private String preProcess(String material) {
        return "*" + material + "——>";
    }
    private String process(String material) {
        return preProcess(material) + "加工——>";
    }
    private String packaging(String material) {
        return process(material) + "包装——>";
    }
    public String processX(String material) {
        return packaging(material) + "产品X";
    }
}

场景类中调用:

public class Client {
    public static void main(String[] args) {
        Factory factory = new Factory();
        System.out.println(factory.processX("原料"));
    }
}

现因业务拓展,工厂增加生产产品Y,产品Y与产品X除了包装不同之外,其它都一样,秉着代码复用,少敲键盘,高效完成工作的原则,对工厂类Factory进行拓展:

public class Factory {
    private String preProcess(String material) {
        return "*" + material + "——>";
    }
    private String process(String material) {
        return preProcess(material) + "加工——>";
    }
    private String packaging(String material) {
        return process(material) + "包装——>";
    }
    public String processX(String material) {
        return packaging(material) + "产品X";
    }
    public String processY(String material) {
        return packaging(material) + "产品Y";
    }
}

场景类Client中,对代码进行调用:

public class Client {
    public static void main(String[] args) {
        Factory factory = new Factory();
        System.out.println(factory.processX("原料"));
        System.out.println(factory.processY("原料"));
    }
}

运行结果如下:

*原料——>加工——>包装——>产品X
*原料——>加工——>包裝——>产品Y

因业务拓展,工厂除了生产产品X,还生产半成品,简单包装一下就可以了,不需要贴上产品X的商标。
因为有现有的预处理,加工,包装方法,为了方便起见,直接将类Factory中的packaging方法,有private改为public,然后由不同的场景类调用,代码如下:

public class Factory {
    private String preProcess(String material) {
        return "*" + material + "——>";
    }
    private String process(String material) {
        return preProcess(material) + "加工——>";
    }
    public String packaging(String material) {
        return process(material) + "包装——>";
    }
    public String processX(String material) {
        return packaging(material) + "产品X";
    }
}
public class Client1 {
    public static void main(String[] args) {
        Factory factory = new Factory();
        System.out.println(factory.processX("原料"));
    }
}
public class Client2 {
    public static void main(String[] args) {
        Factory factory = new Factory();
        System.out.println(factory.packaging("原料"));
    }
}

运行Client1与Client2后,结果如下:

*原料——>加工——>包装——>产品X
*原料——>加工——>包装——>

单一职责要求我们在编写类,抽象类,接口时,要使其功能职责单一纯碎,将导致其变更的因素缩减到最少。
按照这个原则对于工厂类Factory我们重新调整一下实现方案
首先,将四个职责抽取成以下四个接口:

//预处理接口
public interface IPreProcess {
    String preProcess(String material);
}
//加工接口
public interface IProcess {
    String process(String material);
}
//包装接口
public interface IPackaging {
    String packaging(String semiProduct);
}
//产出成品接口
public interface IFactory {
    String process(String product);
}

然后,有四个职责类分别实现这四个接口,如下:

//原料预处理类
public class PreProcess implements IPreProcess{
    @Override
    public String preProcess(String material) {
        return "*" + material + "——>";
    }
}
//加工类
public class Process implements IProcess {
    private IPreProcess preProcess;
    public Process(IPreProcess preProcess) {
        this.preProcess = preProcess;
    }
    @Override
    public String process(String material) {
        return this.preProcess.preProcess(material) + "加工——>";
    }
}
//包装类
public class Packaging implements IPackaging {
    private IProcess process;
    public Packaging(IProcess process) {
        this.process = process;
    }
    @Override
    public String packaging(String material) {
        return this.process.process(material) + "包装——>";
    }
}
//产出成品类
public class FactoryX implements IFactory{
    private Packaging packaging;
    public FactoryX(Packaging packaging) {
        this.packaging = packaging;
    }
    @Override
    public String process(String material) {
        return this.packaging.packaging(material)+ "产品X";
    }
}

场景类中调用代码如下:

public class Client {
    public static void main(String[] args) {
        IFactory factoryX = new FactoryX(new Packaging(new Process(new PreProcess())));
        System.out.println(factoryX.process("原料"));
        IFactory factoryY = new FactoryY(new Packaging(new Process(new PreProcess())));
        System.out.println(factoryY.process("原料"));
    }
}

如果因市场需求,优化产品X的生产方案,改变原料预处理的方式,可以增加一个原料预处理接口IPreProcess的实现类PreProcessA,如下:

//原料预处理类
public class PreProcessA implements IPreProcess{
    @Override
    public String preProcess(String material) {
        return "#" + material + "——>";
    }
}
public class Client {
    public static void main(String[] args) {
        IFactory factoryX = new FactoryX(new Packaging(new Process(new PreProcessA())));
        System.out.println(factoryX.process("原料"));
        IFactory factoryY = new FactoryY(new Packaging(new Process(new PreProcess())));
        System.out.println(factoryY.process("原料"));
    }
}

如果想生产产品X的半成品的话,不需更改生产代码,只需在场景类中直接调用即可:

public class Client {
    public static void main(String[] args) {
        IFactory factoryX = new FactoryX(new Packaging(new Process(new PreProcessA())));
        System.out.println(factoryX.process("原料"));
        IFactory factoryY = new FactoryY(new Packaging(new Process(new PreProcess())));
        System.out.println(factoryY.process("原料"));
        IPackaging packagingX = new Packaging(new Process(new PreProcess()));
        System.out.println(packagingX.packaging("原料"));
    }
}

即使哪天市场需求再变化,再优化产品X的生产方案,改变原料预处理的方式只需再添加个类,实现预处理接口IPreProcess即可,如下:

//原料预处理类
public class PreProcessB implements IPreProcess{
    @Override
    public String preProcess(String material) {
        return "%" + material + "——>";
    }
}

场景类更改如下:

public class Client {

    public static void main(String[] args) {
        IFactory factoryX = new FactoryX(new Packaging(new Process(new PreProcessB())));
        System.out.println(factoryX.process("原料"));
        IFactory factoryY = new FactoryY(new Packaging(new Process(new PreProcess())));
        System.out.println(factoryY.process("原料"));
        IPackaging packagingX = new Packaging(new Process(new PreProcessA()));
        System.out.println(packagingX.packaging("原料"));
    }
}

运行结果如下:

%原料——>加工——>包装——>产品X
*原料——>加工——>包装——>产品Y
#原料——>加工——>包装——>

总而言之,软件设计实际上就是发现职责并将职责相互分离,所以在编写代码时更多的应该考虑单一职责这种设计模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值