设计模式的分类


总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。



设计模式的六大原则

1、开闭原则(Open Close Principle)

对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科

3、依赖倒转原则(Dependence Inversion Principle)

这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

5、迪米特法则(最少知道原则)(Demeter Principle)

为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

原则是尽量使用合成/聚合的方式,而不是使用继承。



一、创建型模式

1、简单工厂模式

一个工厂 可以生产很多的产品。包含一个接口和若干个实现类,以及一个工厂来生产这些实现类。我们以生产Fruit来加以说明

类图如下:

Java工厂模式的应用 java工厂模式和策略模式_ci

接口Fruit


package org.czty.simpleFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public interface Fruit {
    public void display();
}

实现类Apple


package org.czty.simpleFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class Apple implements Fruit{

    @Override
    public void display() {
        System.out.println("生产了一个苹果");
    }
}

实现类Orange


package org.czty.simpleFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class Orange implements Fruit {
    @Override
    public void display() {
        System.out.println("生产了一个橘子");
    }
}

工厂类Factory


package org.czty.simpleFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class Factory {
    public Fruit create(int type) {
        Fruit fruit = null;
        switch (type) {
            case 0:
                fruit = new Apple();
                break;
            case 1:
                fruit = new Orange();
                break;
        }
        return fruit;
    }
}

测试类


package org.czty.simpleFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class Test {
    public static void main(String[] args) {
        Factory factory = new Factory();
        factory.create(0).display();
        factory.create(1).display();
    }
}

测试结果:


生产了一个苹果
生产了一个橘子

Process finished with exit code 0


总结:

简单工厂模式其实非常简单,生产实例的过程在工厂执行,并且选择的过程也是在工厂中执行的。这样如果新增了新的实现,比如香蕉,那么就要改工厂类,这就违背了可拓展的原则。而用另一种工厂方法模式很好的解决了这个问题。使得改动只发生在客户端,不会对原来的类进行修改。

多个工厂模式


类图如下:

Java工厂模式的应用 java工厂模式和策略模式_工厂模式_02



较之上面的类图,多了一个factory,这样一旦有新的的实现加入,只需要再加入新的工厂,这样就不用改变原有的代码了。


代码只是在原有的基础上新增了两个工厂类

AppleFactory


package org.czty.simpleFactory2;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class AppleFactory {
    public Fruit createApple() {
        Fruit fruit = new Apple();
        return fruit;
    }
}

OrangeFactory


package org.czty.simpleFactory2;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class OrangeFactory {
    public Fruit createOrange() {
        Fruit fruit = new Orange();
        return fruit;
    }
}

测试类


package org.czty.simpleFactory2;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class Test {
    public static void main(String[] args) {
        Fruit fruit = new AppleFactory().createApple();
        fruit.display();
        fruit = new OrangeFactory().createOrange();
        fruit.display();
    }
}

结果


生产了一个苹果
生产了一个橘子

Process finished with exit code 0


结果和简单工厂模式一样,但是多个工厂模式具有更好的可拓展性,且把判断逻辑移到了客户端。但同样带来问题,每个实现对应一个工厂类太麻烦了,解决办法就是反射机制。

Claa.forName("package.class").newInstance();
我们修改一下工厂类

ReflectFactory


package org.czty.simpleFactory2;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class ReflectFactory {
    public static Fruit getInstance(String className) {
        Fruit fruit = null;
        try {
            fruit = (Fruit) Class.forName(className).newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return fruit;
    }
}

测试类


package org.czty.simpleFactory2;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class Test {
    public static void main(String[] args) {
        /*Fruit fruit = new AppleFactory().createApple();
        fruit.display();
        fruit = new OrangeFactory().createOrange();
        fruit.display();*/原来的代码
        Fruit fruit = ReflectFactory.getInstance("org.czty.simpleFactory2.Apple");
        if (fruit != null) {
            fruit.display();
        }
    }
}

发现只需要一个工厂就能搞定,避免了为每一个实现类单独写一个工厂了。




抽象工厂模式

工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式。与之前不同,这里不再是一个接口,而是两个接口,即划分事务的方式存在了两个维度。创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
用猫和狗来做例子,猫有白猫和黑猫,狗有白狗和黑狗。

维度1:按动物划分,猫和狗

维度2:按颜色划分,黑和白

对于接口是按照动物类型划分的。而工厂则是按照颜色类型划分的。即一个工厂可以生产一个颜色的两种动物类型。类图如下

Java工厂模式的应用 java工厂模式和策略模式_工厂类_03

代码实现

Dog接口

package org.czty.abstractFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public interface Dog {
    public void create();
}

Cat接口


package org.czty.abstractFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public interface Cat {
    public void create();
}

BlackDog实现类


package org.czty.abstractFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class BlackDog implements Dog {
    @Override
    public void create() {
        System.out.println("生产了一只黑狗");
    }
}

WhiteDog实现类


package org.czty.abstractFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class WhiteDog implements Dog {
    @Override
    public void create() {
        System.out.println("生产了一只白狗");
    }
}

BlackCat实现类


package org.czty.abstractFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class BlackCat implements Cat {
    @Override
    public void create() {
        System.out.println("生产了一只黑猫");
    }
}

WhiteCat实现类


package org.czty.abstractFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class WhiteCat implements Cat {
    @Override
    public void create() {
        System.out.println("生产了一只白猫");
    }
}

BlackFactory工厂类


package org.czty.abstractFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class BlackFactory {
    public Dog createBlackDog() {
        return new BlackDog();
    }
    public Cat createBlackCat() {
        return new BlackCat();
    }
}

WhiteFactory工厂类


package org.czty.abstractFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class WhiteFactory {
    public Dog createWhiteDog() {
        return new WhiteDog();
    }
    public Cat createWhiteCat() {
        return new WhiteCat();
    }
}

测试类


package org.czty.abstractFactory;

/**
 * Created by Chris chen on 2017/8/5.
 */
public class Test {
    public static void main(String[] args) {
        BlackFactory blackFactory = new BlackFactory();
        blackFactory.createBlackCat().create();
        blackFactory.createBlackDog().create();
        WhiteFactory whiteFactory = new WhiteFactory();
        whiteFactory.createWhiteCat().create();
        whiteFactory.createWhiteDog().create();
    }
}

结果


生产了一只黑猫
生产了一只黑狗
生产了一只白猫
生产了一只白狗

Process finished with exit code 0