通过Java代码来理解设计模式的七大原则(一)

单一职责原则

定义很简单:一个类只负责一项职责,这就叫单一职责原则。先来看一个Demo

public class SingleResponsibility1 {
    public static void main(String[] args) {
        new Animal().eat("猫");
        new Animal().eat("兔子");
        //运行结果:
        /**
        *猫吃肉
        *兔子吃肉
        */
    }
}
class Animal{
    public void eat(String animal){
        System.out.println(animal+"吃肉");
    }
}

兔子并不是吃肉的,很明显,这里的Animal类既负责吃肉的动物,又负责吃素的动物,违背了单一职责原则。而最容易想到的改进方法就是将Animal类细分为肉食动物类和素食动物类两个类:

public class SingleResponsibility2 {
    public static void main(String[] args) {
        new MeatAnimal().eat("猫");
        new GrassAnimal().eat("兔子");
        //运行结果:
        /**
        *猫吃肉
        *兔子吃草
        */
    }
}
class MeatAnimal{
    public void eat(String animal){
        System.out.println(animal+"吃肉");
    }
}
class GrassAnimal{
    public  void eat(String animal){
        System.out.println(animal+"吃草");
    }
}

但是这种方式不仅要将原来的类分解,还要改动客户端(main方法)里的代码,因此代码的可维护性较差,不是理想的方案,下面再给出一种改动方案:

public class SingleResponsibility3 {
    public static void main(String[] args) {
        new Animal().eat1("猫");
        new Animal().eat2("兔子");
    }
}
class Animal{
    public void eat1(String animal){
        System.out.println(animal+"吃肉");
    }
    public void eat2(String animal){
        System.out.println(animal+"吃草");
    }
}

这种方案实质上并不是类的单一职责原则,而是方法上的单一职责原则,相比上面两种要好一些。这三种方案,一种比一种好,但第三种也不是最好的,总之,如果仅仅只用单一职责原则,确实能够对代码优化,但要达到最优,有时候用的不仅仅是一种原则。七大原则中的好几条可能要一起用才行,还是这个例子,看第四个Demo

public class SingleResponsibility4 {
    public static void main(String[] args) {
        new Animal().eat(new Cat());
        new Animal().eat(new Rabbit());
    }
}
class Animal{
    //Animal的eat方法是对接口Eat的依赖
    public void eat(Eat eat){
        System.out.println(eat.getEatType());
    }
}
interface Eat{
    public String getEatType();
}
class Cat implements Eat{
    @Override
    public String getEatType() {
        return "猫吃肉";
    }
}
class Rabbit implements Eat{

    @Override
    public String getEatType() {
        return "兔子吃草";
    }
}

别看这个代码这么长,但是第四种相比前三种来说,可维护性可扩展性要高得多,这种方式,既遵守了单一职责原则,又遵守了依赖倒转原则,就是我上面说的,同时遵守多种原则的情况,简单说说这第四种为什么可维护性和可扩展性高?

  • 如果现在新增了一个长颈鹿的动物,长颈鹿是吃树叶的
  • 那么main方法里之前的东西不用改,只需要往后面加就行了(可扩展性体现)
  • Animal类完全不需要任何修改
  • Eat接口完全不需要任何修改
  • 只需要新增一个Giraffe类去实现Eat接口,并重写getEatType方法就ok
  • 从上面我们可以看出,一旦实际需求发送变化,只需要做很小的改动,并且只是“增加”/“删除”这种操作,完全没有“修改”这种操作

再来看看增加一个长颈鹿,代码怎么写:

public class SingleResponsibility4 {
    public static void main(String[] args) {
        new Animal().eat(new Cat());
        new Animal().eat(new Rabbit());
        new Animal().eat(new Giraffe());
    }
}
class Animal{
    //Animal的eat方法是对接口Eat的依赖
    public void eat(Eat eat){
        System.out.println(eat.getEatType());
    }
}
interface Eat{
    public String getEatType();
}
class Cat implements Eat{
    @Override
    public String getEatType() {
        return "猫吃肉";
    }
}
class Rabbit implements Eat{

    @Override
    public String getEatType() {
        return "兔子吃草";
    }
}
class Giraffe implements Eat{

    @Override
    public String getEatType() {
        return "长颈鹿吃树叶";
    }
}

接口隔离原则

定义:一个类对另一个类的依赖应该建立在最小的接口上;先看一个UML图:
在这里插入图片描述
做个说明:

  • A通过Intergace1会依赖B,但A中只会使用到接口的1,2,3这三个方法
  • C通过Intergace1会依赖D,但C中只会使用到接口的1,4,5这三个方法

先按照以上的UML图来写下代码:

public class InterfacePrinciple {
    public static void main(String[] args) {
        A a = new A();
        a.depend1(new B());
        a.depend2(new B());
        a.depend3(new B());

        C c = new C();
        c.depend1(new D());
        c.depend4(new D());
        c.depend5(new D());
        /**
         * 运行结果:
         * B实现了operation1方法
         * B实现了operation2方法
         * B实现了operation3方法
         * D实现了operation1方法
         * D实现了operation4方法
         * D实现了operation5方法
         */

    }
}
interface Interface1{
    void operation1();
    void operation2();
    void operation3();
    void operation4();
    void operation5();
}
class B implements Interface1{

    @Override
    public void operation1() {
        System.out.println("B实现了operation1方法");
    }

    @Override
    public void operation2() {
        System.out.println("B实现了operation2方法");
    }

    @Override
    public void operation3() {
        System.out.println("B实现了operation3方法");
    }

    @Override
    public void operation4() {
        System.out.println("B实现了operation4方法");
    }

    @Override
    public void operation5() {
        System.out.println("B实现了operation5方法");
    }
}
class D implements Interface1{

    @Override
    public void operation1() {
        System.out.println("D实现了operation1方法");
    }

    @Override
    public void operation2() {
        System.out.println("D实现了operation2方法");
    }

    @Override
    public void operation3() {
        System.out.println("D实现了operation3方法");
    }

    @Override
    public void operation4() {
        System.out.println("D实现了operation4方法");
    }

    @Override
    public void operation5() {
        System.out.println("D实现了operation5方法");
    }
}
class A{
    public void depend1(Interface1 m){
        m.operation1();
    }
    public void depend2(Interface1 m){
        m.operation2();
    }
    public void depend3(Interface1 m){
        m.operation3();
    }
}

class C{
    public void depend1(Interface1 m){
        m.operation1();
    }
    public void depend4(Interface1 m){
        m.operation4();
    }
    public void depend5(Interface1 m){
        m.operation5();
    }
}

从这个代码以及运行结果来看,B和D两个类都实现了Interface1里的所有方法,然而A和C通过接口去依赖BD,仅仅只用到了一部分方法,也就是说,对B来说,operation4和operation5白写了,因为A根本用不到这两个。同样的,对D来说,operation2和operation3也白写了,C也用不到这两个。因此,以上的UML类图需要做出改动:
在这里插入图片描述
这一种设计方案,就叫做接口隔离,具体代码我就懒得贴上来了,总之,接口隔离的目的,就是:用不到的方法就隔离,手法是拆分原来的接口,分别去实现和依赖。

依赖倒转原则

四句话可以概括它:

  • 高层模块不应该依赖低层模块,二者都应该依赖其抽象
  • 抽象不应该依赖细节,细节应该依赖抽象
  • 依赖倒转的本质是面向接口编程
  • 抽象比细节要稳定的多,抽象指的是接口或抽象类,细节指的是实现类/继承类

在上面单一职责原则的最后一个Demo的代码就用到了依赖倒转原则,现在再单独写一个别的:

public class DependenceInversion {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.receive(new Email());
        /**
         * 运行结果:
         * 收到电子邮件信息,信息内容为:“hello,jack”
         */
    }
}

class Email {
    public String getInfo() {
        return "收到电子邮件信息,信息内容为:“hello,jack”";
    }
}

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

来分析一下以上代码:

  • 手机收到信息,如果收到的是Email信息,就像上面那样写ok,如果收到的是微信信息,QQ信息等,那么在Phone这个类里面,就还要增加WeiXin以及QQ的receive方法
  • 还能怎么做呢?还可以引入一个接口InfoSource,表示信息来源;而Email,QQ,WeiXin就属于一系列的信息来源,因此,它们可以作为InfoSource的实现类,下面用代码来写一个:
public class DependenceInversion {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.receive(new Email());
        phone.receive(new WeiXin());
        /**
         * 运行结果:
         * 收到电子邮件信息,信息内容为:“hello,jack”
         * 收到微信信息,信息内容为:“GoodBye,jack”
         */
    }
}

class Phone {//这里是对接口的依赖,因此即便有新的信息种类来源,这里也不需要更改
    public void receive(InfoSource infoSource) {
        System.out.println(infoSource.getInfo());
    }
}

interface InfoSource {
    String getInfo();
}

class Email implements InfoSource {
    @Override
    public String getInfo() {
        return "收到电子邮件信息,信息内容为:“hello,jack”";
    }
}

class WeiXin implements InfoSource {
    @Override
    public String getInfo() {
        return "收到微信信息,信息内容为:“GoodBye,jack”";
    }
}

依赖关系的三种传递方式

  • 基于接口的传递
public class DependenceInversion {
    public static void main(String[] args) {
        new Email().receive(new InfoSource() {
            @Override
            public void getInfo() {
                System.out.println("收到Email信息,内容为:“你好帅呀”");
            }
        });
        new Email().send(new InfoSource() {
            @Override
            public void getInfo() {
                System.out.println("发送Email信息,内容为:“你更帅”");
            }
        });
        new WeiXin().receive(new InfoSource() {
            @Override
            public void getInfo() {
                System.out.println("收到微信信息,内容为:“你好丑啊”");
            }
        });
        new WeiXin().send(new InfoSource() {
            @Override
            public void getInfo() {
                System.out.println("发送微信信息,内容为:“你比我更丑”");
            }
        });
        /**
         * 运行结果:
         * 收到Email信息,内容为:“你好帅呀”
         * 发送Email信息,内容为:“你更帅”
         * 收到微信信息,内容为:“你好丑啊”
         * 发送微信信息,内容为:“你比我更丑”
         */
    }
}


interface ReceiveOrSend {//接收或者发送
	//两个抽象方法都接收了接口
    void receive(InfoSource infoSource);

    void send(InfoSource infoSource);
}

interface InfoSource {//信息

    void getInfo();//信息具体内容
}

class Email implements ReceiveOrSend {

    @Override
    public void receive(InfoSource infoSource) {
        infoSource.getInfo();
    }

    @Override
    public void send(InfoSource infoSource) {
        infoSource.getInfo();
    }
}

class WeiXin implements ReceiveOrSend {

    @Override
    public void receive(InfoSource infoSource) {
        infoSource.getInfo();
    }

    @Override
    public void send(InfoSource infoSource) {
        infoSource.getInfo();
    }
}
  • 基于构造器传递
public class DependenceInversion {
    public static void main(String[] args) {
        new Email(new InfoSource() {
            @Override
            public void getInfo() {
                System.out.println("收到Email信息,内容为:“你好帅呀”");
            }
        }).receive();
        new Email(new InfoSource() {
            @Override
            public void getInfo() {
                System.out.println("发送Email信息,内容为:“你更帅”");
            }
        }).send();
        new WeiXin(new InfoSource() {
            @Override
            public void getInfo() {
                System.out.println("收到微信信息,内容为:“你好丑啊”");
            }
        }).receive();
        new WeiXin(new InfoSource() {
            @Override
            public void getInfo() {
                System.out.println("发送微信信息,内容为:“你比我更丑”");
            }
        }).send();
        /**
         * 运行结果:
         * 收到Email信息,内容为:“你好帅呀”
         * 发送Email信息,内容为:“你更帅”
         * 收到微信信息,内容为:“你好丑啊”
         * 发送微信信息,内容为:“你比我更丑”
         */
    }
}


interface ReceiveOrSend {//接收或者发送
    //两个抽象方法没有接收接口
    void receive();

    void send();
}

interface InfoSource {//信息

    void getInfo();//信息具体内容
}

class Email implements ReceiveOrSend {
    public InfoSource mInfoSource;
    public Email(InfoSource infoSource){
        mInfoSource = infoSource;
    }
    @Override
    public void receive() {
        mInfoSource.getInfo();
    }

    @Override
    public void send() {
        mInfoSource.getInfo();
    }
}

class WeiXin implements ReceiveOrSend {
    public InfoSource mInfoSource;
    public WeiXin(InfoSource infoSource){
        mInfoSource = infoSource;
    }
    @Override
    public void receive() {
        mInfoSource.getInfo();
    }

    @Override
    public void send() {
        mInfoSource.getInfo();
    }
}
  • 通过setter方法传递
public class DependenceInversion {
    public static void main(String[] args) {
        Email email = new Email();
        email.setInfo(new InfoSource() {
            @Override
            public void getInfo() {
                System.out.println("收到Email信息,内容为:“你好帅呀”");
            }
        });
        email.receive();
        email.setInfo(new InfoSource() {
            @Override
            public void getInfo() {
                System.out.println("发送Email信息,内容为:“你更帅”");
            }
        });
        email.send();
        WeiXin weiXin = new WeiXin();
        weiXin.setInfo(new InfoSource() {
            @Override
            public void getInfo() {
                System.out.println("收到微信信息,内容为:“你好丑啊”");
            }
        });
        weiXin.receive();
        weiXin.setInfo(new InfoSource() {
            @Override
            public void getInfo() {
                System.out.println("发送微信信息,内容为:“你比我更丑”");
            }
        });
        weiXin.send();
        /**
         * 运行结果:
         * 收到Email信息,内容为:“你好帅呀”
         * 发送Email信息,内容为:“你更帅”
         * 收到微信信息,内容为:“你好丑啊”
         * 发送微信信息,内容为:“你比我更丑”
         */
    }
}


interface ReceiveOrSend {//接收或者发送
    //两个抽象方法没有接收接口
    void receive();

    void send();
	//新增了一个setter方法
    void setInfo(InfoSource infoSource);
}

interface InfoSource {//信息

    void getInfo();//信息具体内容
}

class Email implements ReceiveOrSend {
    public InfoSource mInfoSource;

    @Override
    public void receive() {
        mInfoSource.getInfo();
    }

    @Override
    public void send() {
        mInfoSource.getInfo();
    }

    @Override
    public void setInfo(InfoSource infoSource) {
        mInfoSource = infoSource;
    }
}

class WeiXin implements ReceiveOrSend {
    public InfoSource mInfoSource;

    @Override
    public void receive() {
        mInfoSource.getInfo();
    }

    @Override
    public void send() {
        mInfoSource.getInfo();
    }

    @Override
    public void setInfo(InfoSource infoSource) {
        mInfoSource = infoSource;
    }
}

七大原则已经写了3个,后面4个下一篇博客再接着写

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值