Radio

一个小小程序员

0%

过滤器模式

过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。这种类型的设计模式属于结构型模式,它结合多个标准来获得单一标准。

示例演示:
  1. 我们创建一个people实体

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package test.filter;

    import lombok.Data;

    @Data
    public class People {

    private Integer id;
    private String name;

    public People(Integer id, String name) {
    this.id = id;
    this.name = name;
    }
    }
  2. 创建一个peopleId的接口,用于通过id对people分组

    1
    2
    3
    4
    5
    6
    7
    package test.filter;

    import java.util.List;

    public interface PeopleId {
    public List<People> group(List<People> peoples);
    }
  3. 接下来我们按照奇偶对id进行分类,我们创建两个实现类分班对group进行实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package test.filter;

    import java.util.ArrayList;
    import java.util.List;

    public class OddPeople implements PeopleId {
    @Override
    public List<People> group(List<People> peoples) {
    List<People> oddPeoples = new ArrayList<>();
    for (People people : peoples) {
    if (people.getId() % 2 != 0) {
    oddPeoples.add(people);
    }
    }
    return oddPeoples;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package test.filter;

    import java.util.ArrayList;
    import java.util.List;

    public class EvenPeople implements PeopleId {
    @Override
    public List<People> group(List<People> peoples) {
    List<People> evenPeoples = new ArrayList<>();
    for (People people : peoples) {
    if (people.getId() % 2 == 0) {
    evenPeoples.add(people);
    }
    }
    return evenPeoples;
    }
    }
  4. 完成上述步骤,我们就可以开始演示了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    package test.filter;

    import java.util.ArrayList;
    import java.util.List;

    public class FilterDemo {
    public static void main(String[] args) {
    List<People> peoples = new ArrayList<>();

    peoples.add(new People(1,"1"));
    peoples.add(new People(2,"2"));
    peoples.add(new People(3,"3"));
    peoples.add(new People(4,"4"));
    peoples.add(new People(5,"5"));
    peoples.add(new People(6,"6"));
    peoples.add(new People(7,"7"));
    peoples.add(new People(8,"8"));
    peoples.add(new People(9,"9"));
    peoples.add(new People(10,"10"));

    PeopleId oddPeople = new OddPeople();
    System.out.println(oddPeople.group(peoples).toString());

    PeopleId evenPeople = new EvenPeople();
    System.out.println(evenPeople.group(peoples).toString());

    }
    }

    运行结果:

    1
    2
    [People(id=1, name=1), People(id=3, name=3), People(id=5, name=5), People(id=7, name=7), People(id=9, name=9)]
    [People(id=2, name=2), People(id=4, name=4), People(id=6, name=6), People(id=8, name=8), People(id=10, name=10)]
    说明:

    过滤器模式就是我们对一组对象进行过滤,java8提供了里面就提供了很多方法来过滤数据,比如刚才的按照奇偶分类我们就可以直接使用java8提供的方法:

    1
    Map<Integer, List<People>> groupList = peoples.stream().collect(Collectors.groupingBy(c -> c.getId()%2));

桥接模式

桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。

这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。

示例演示:
  1. 我们创建一个性别api接口

    1
    2
    3
    4
    5
    package test.bridge;

    public interface SexApi {
    public void sex();
    }
  2. 创建两个接口实现

    1
    2
    3
    4
    5
    6
    7
    8
    package test.bridge;

    public class Male implements SexApi {
    @Override
    public void sex() {
    System.out.println("my sex is male");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    package test.bridge;

    public class Female implements SexApi {
    @Override
    public void sex() {
    System.out.println("my sex is female");
    }
    }
  3. 创建一个people的抽象类,并赋予性别api的接口功能,为people提供一个性别

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package test.bridge;

    public abstract class People {
    protected SexApi sexApi;

    protected People(SexApi sexApi) {
    this.sexApi = sexApi;
    }
    public abstract void peopleSex();
    }
  4. 创建people的实体类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package test.bridge;

    public class PeopleImpl extends People{

    protected PeopleImpl(SexApi sexApi) {
    super(sexApi);
    }

    @Override
    public void peopleSex() {
    sexApi.sex();
    }
    }
  5. 完成上述步骤,我们就可以开始演示了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package test.bridge;

    public class BridgeDemo {
    public static void main(String[] args) {
    People male = new PeopleImpl(new Male());
    People female = new PeopleImpl(new Female());

    male.peopleSex();
    female.peopleSex();
    }
    }

    运行结果:

    1
    2
    my sex is male
    my sex is female
说明:

优点: 1、抽象和实现的分离。 2、优秀的扩展能力。 3、实现细节对客户透明。

缺点:桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。

适配器模式

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。

示例演示:
  1. 由于我们之前的例子都是围绕people和animal来的,所以我们依然用people来举例,例子可能不太恰当,网上有更好的例子;这次我们把people设计成一个接口,这个接口提供了一个eat的方法,方法有两个参数,什么类型的食物,和食物名称

    1
    2
    3
    4
    5
    package test.adapter;

    public interface People {
    public void eat(String type, String name);
    }
  2. 这时候我们新增两个接口,一个吃荤,一个吃素

    1
    2
    3
    4
    5
    6
    7
    package test.adapter;

    public interface AdvancedPeople {

    public void eatMeat(String name);
    public void eatVege(String name);
    }
  3. 然后我们创建两个实体类,分别来实现这俩方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package test.adapter;

    public class PeopleEatMeat implements AdvancedPeople{
    @Override
    public void eatMeat(String name) {
    System.out.println("eat meat :"+name);
    }

    @Override
    public void eatVege(String name) {

    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package test.adapter;

    public class PeopleEatVege implements AdvancedPeople{
    @Override
    public void eatMeat(String name) {

    }

    @Override
    public void eatVege(String name) {
    System.out.println("eat vege :"+name);
    }
    }
  4. 接下来重点来了,我们创建一个适配eat的适配器实现类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package test.adapter;

    public class PeopleAdapter implements People {
    AdvancedPeople advancedPeople;

    public PeopleAdapter(String type) {
    if (type.equalsIgnoreCase("meat")) {
    advancedPeople = new PeopleEatMeat();
    } else if (type.equalsIgnoreCase("vege")) {
    advancedPeople = new PeopleEatVege();
    }
    }

    @Override
    public void eat(String type, String name) {
    if (type.equalsIgnoreCase("meat")) {
    advancedPeople.eatMeat(name);
    } else if (type.equalsIgnoreCase("vege")) {
    advancedPeople.eatVege(name);
    }
    }
    }
  5. 创建一个people接口实现类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package test.adapter;

    public class PeopleImpl implements People {
    PeopleAdapter peopleAdapter;

    @Override
    public void eat(String type, String name) {
    if (type.equalsIgnoreCase("food")) {
    System.out.println("eat food :"+name);
    }else if (type.equalsIgnoreCase("meat") || type.equalsIgnoreCase("vege")){
    peopleAdapter = new PeopleAdapter(type);
    peopleAdapter.eat(type,name);
    }else if (type.equalsIgnoreCase("fruit")){
    System.out.println(name+" not supported");
    }
    }
    }
  6. 完成上述步骤,我们就可以开始演示了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package test.adapter;

    public class AdapterDemo {
    public static void main(String[] args) {
    PeopleImpl people = new PeopleImpl();
    people.eat("food","rice");
    people.eat("meat","fish");
    people.eat("vege","tomato");
    people.eat("fruit","apple");
    }
    }

    运行结果:

    1
    2
    3
    4
    eat food :rice
    eat meat :fish
    eat vege :tomato
    apple not supported
说明:

优点: 1、可以让任何两个没有关联的类一起运行。 2、提高了类的复用。 3、增加了类的透明度。 4、灵活性好。

缺点: 1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。 2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

示例演示:
  1. 创建一个抽象类,实现Cloneable接口,提供一个抽象方法,重写Object的clone方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package test.prototype;

    import lombok.Data;

    @Data
    public abstract class People implements Cloneable {

    private Integer id;

    protected String type;

    abstract void say();

    public Object clone() {
    Object clone = null;
    try {
    clone = super.clone();
    } catch (CloneNotSupportedException e) {
    e.printStackTrace();
    }
    return clone;
    }
    }
  2. 创建两个people实体类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    package test.prototype;

    public class PeopleOne extends People{
    public PeopleOne(){
    type="peopleone";
    }

    @Override
    public void say() {
    System.out.println("my name is peopleone");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    package test.prototype;

    public class PeopleTwo extends People{
    public PeopleTwo(){
    type="peopletwo";
    }

    @Override
    public void say() {
    System.out.println("my name is peopletwo");
    }
    }
  3. 创建一个存放原型对象的注册表,提供一个获取新实例的方法,用来复制原型,默认初始化两个实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package test.prototype;

    import java.util.Hashtable;

    public class PeopleCache {
    private static Hashtable<Integer, People> peopleMap = new Hashtable<>();

    public static People getPeople(Integer id) {
    People people = peopleMap.get(id);
    //复制一个新的实例,属于浅拷贝
    return (People) people.clone();
    }

    public static void loadCache() {
    PeopleOne peopleOne = new PeopleOne();
    peopleOne.setId(1);
    peopleMap.put(peopleOne.getId(), peopleOne);

    PeopleTwo peopleTwo = new PeopleTwo();
    peopleTwo.setId(2);
    peopleMap.put(peopleTwo.getId(), peopleTwo);
    }
    }
  4. 完成上述步骤,我们就可以开始演示了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package test.prototype;

    public class PrototypeDemo {
    public static void main(String[] args) {
    PeopleCache.loadCache();
    People peopleOne = PeopleCache.getPeople(1);
    System.out.println(peopleOne.type);
    peopleOne.say();

    People peopleTwo = PeopleCache.getPeople(2);
    System.out.println(peopleTwo.type);
    peopleTwo.say();
    }
    }

    新生成的两个实例就是通过原型clone出来的

    运行结果:

    1
    2
    3
    4
    peopleone
    my name is peopleone
    peopletwo
    my name is peopletwo
说明:

优点: 1、性能提高。 2、逃避构造函数的约束。

缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。

建造者模式

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

StringBuilder就是典型的建造者模式

示例演示:
  1. 这次我们的类会变的复杂一些,我们还是老规矩,先创建一个Organism接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    package test.builder;

    /**
    * 所有生物的标识
    */
    public interface Organism {
    //所有生物共有的一个功能,有自己的沟通方式
    String say();
    }
  2. 我们先不创建people和animal,我们先创建一个条目,让这个条目来融合Organism,同时我们新增两个属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package test.builder;

    public abstract class PeopleItem implements Item {
    @Override
    public Organism organism() {
    return new People();
    }

    @Override
    public abstract String name();

    @Override
    public abstract Integer Height();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package test.builder;

    public abstract class AnimalItem implements Item {
    @Override
    public Organism organism() {
    return new Animal();
    }

    @Override
    public abstract String name();

    @Override
    public abstract Integer Height();
    }
  3. 两个抽象的条目创建好了,我们只实现其中的Organism,名字和身高,我们让具体类去实现,我们创建两个人,两个动物分别实现名字和身高。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package test.builder;

    public class PeopleItemOne extends PeopleItem {

    @Override
    public String name() {
    return "my name is peopleOne";
    }

    @Override
    public Integer Height() {
    return 100;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package test.builder;

    public class PeopleItemTwo extends PeopleItem {

    @Override
    public String name() {
    return "my name is peopleTwo";
    }

    @Override
    public Integer Height() {
    return 200;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package test.builder;

    public class AnimalItemOne extends AnimalItem {
    @Override
    public String name() {
    return "my name is animalOne";
    }

    @Override
    public Integer Height() {
    return 50;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package test.builder;

    public class AnimalItemTwo extends AnimalItem {
    @Override
    public String name() {
    return "my name is animalTwo";
    }

    @Override
    public Integer Height() {
    return 100;
    }
    }
  4. 我们创建一个家庭成员的类,让他帮我们归纳一下哪些人,哪些动物属于哪个家庭,做一下统计

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    package test.builder;

    import java.util.ArrayList;
    import java.util.List;

    public class Family {
    private List<Item> items = new ArrayList<>();

    public void addItem(Item item) {
    items.add(item);
    }

    public Integer getHeight() {
    Integer height = 0;
    for (Item item : items) {
    height += item.Height();
    }
    return height;
    }

    public void showItems() {
    for (Item item : items) {
    System.out.println("Item: " + item.name());
    System.out.println("say:" + item.organism().say());
    System.out.println("height:" + item.Height());
    }
    }
    }
  5. 方便起见,我们创建两个家庭,分别设置一些成员

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package test.builder;

    public class FamilyBuilder {

    public Family familyOne() {
    Family family = new Family();
    family.addItem(new PeopleItemOne());
    family.addItem(new PeopleItemTwo());
    family.addItem(new AnimalItemOne());
    return family;
    }

    public Family familyTwo() {
    Family family = new Family();
    family.addItem(new PeopleItemTwo());
    family.addItem(new AnimalItemTwo());
    return family;
    }
    }
  6. 完成上述步骤,我们就可以开始演示了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package test.builder;

    public class BuilderDemo {
    public static void main(String[] args) {
    FamilyBuilder familyBuilder = new FamilyBuilder();
    Family familyOne = familyBuilder.familyOne();
    familyOne.showItems();
    System.out.println("身高和:" + familyOne.getHeight());
    System.out.println("---------------------------------");
    Family familyTwo = familyBuilder.familyTwo();
    familyTwo.showItems();
    familyTwo.getHeight();
    System.out.println("身高和:" + familyTwo.getHeight());
    }
    }

    运行结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Item: my name is peopleOne
    say:people say
    height:100
    Item: my name is peopleTwo
    say:people say
    height:200
    Item: my name is animalOne
    say:animal say
    height:50
    身高和:350
    ---------------------------------
    Item: my name is peopleTwo
    say:people say
    height:200
    Item: my name is animalTwo
    say:animal say
    height:100
    身高和:300
说明:

优点:1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

相当于把所有工厂又封装了一遍。

示例演示:
  1. 模仿工厂模式,我们创建两个接口,一个生物,一个性别,分别有两个实现类

    1
    2
    3
    4
    5
    6
    7
    8
    package test.abstractFactory;
    /**
    * 所有生物的标识
    */
    public interface Organism {
    //所有生物共有的一个功能,有自己的沟通方式
    void say();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    package test.abstractFactory;

    public class People implements Organism{

    @Override
    public void say() {
    System.out.println("people say");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    package test.abstractFactory;

    public class Animal implements Organism{

    @Override
    public void say() {
    System.out.println("animal say");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    package test.abstractFactory;
    /**
    * 所有生物都有性别
    */
    public interface Sex {

    void sex();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    package test.abstractFactory;

    public class Male implements Sex {
    @Override
    public void sex() {
    System.out.println("male");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    package test.abstractFactory;

    public class Female implements Sex {
    @Override
    public void sex() {
    System.out.println("female");
    }
    }
  2. 创建一个超级工厂

    1
    2
    3
    4
    5
    6
    7
    8
    9
    package test.abstractFactory;

    public abstract class AbstractFactory {

    public abstract Organism getOrganism(String type);

    public abstract Sex getSex(String type);

    }
  3. 通过继承超级工厂来分别来实现各自的工厂

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    package test.abstractFactory;

    import org.apache.commons.lang3.StringUtils;

    public class OrganismFactory extends AbstractFactory{

    @Override
    public Organism getOrganism(String type) {
    if (StringUtils.isBlank(type)) {
    return null;
    }
    if (type.equalsIgnoreCase("people")) {
    return new People();
    } else if (type.equalsIgnoreCase("animal")) {
    return new Animal();
    }
    return null;
    }

    @Override
    public Sex getSex(String type) {
    return null;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    package test.abstractFactory;

    import org.apache.commons.lang3.StringUtils;

    public class SexFactory extends AbstractFactory{

    @Override
    public Organism getOrganism(String type) {
    return null;
    }

    @Override
    public Sex getSex(String type) {
    if (StringUtils.isBlank(type)) {
    return null;
    }
    if (type.equalsIgnoreCase("male")) {
    return new Male();
    } else if (type.equalsIgnoreCase("female")) {
    return new Female();
    }
    return null;
    }
    }
  4. 创建一个工厂创造器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package test.abstractFactory;

    import org.apache.commons.lang3.StringUtils;

    public class FactoryProducer {

    public static AbstractFactory getFactory(String type) {
    if (StringUtils.isBlank(type)) {
    return null;
    }
    if (type.equalsIgnoreCase("organism")) {
    return new OrganismFactory();
    } else if (type.equalsIgnoreCase("sex")) {
    return new SexFactory();
    }
    return null;
    }
    }
  5. 完成上述步骤,我们就可以开始演示了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package test.abstractFactory;

    public class AbstractFactoryDemo {
    public static void main(String[] args) {
    AbstractFactory organismFactory = FactoryProducer.getFactory("organism");
    Organism people = organismFactory.getOrganism("people");
    people.say();

    Organism animal = organismFactory.getOrganism("animal");
    animal.say();

    AbstractFactory sexFactory = FactoryProducer.getFactory("sex");

    Sex male = sexFactory.getSex("male");
    male.sex();

    Sex female = sexFactory.getSex("female");
    female.sex();

    }
    }

    运行结果:

    1
    2
    3
    4
    people say
    animal say
    male
    female
说明:

优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。

工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

示例演示:
  1. 我们定义一个生物接口,生物接口中有一个说话的功能。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    package test.factory;

    /**
    * 所有生物的标识
    */
    public interface Organism {
    //所有生物共有的一个功能,有自己的沟通方式
    void say();
    }
  2. 创建两个实体类,让其拥有Organism的属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    package test.factory;

    public class People implements Organism {

    @Override
    public void say() {
    System.out.println("people say");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    package test.factory;

    public class Animal implements Organism {

    @Override
    public void say() {
    System.out.println("animal say");
    }
    }
  3. 创建产生对象的工厂

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package test.factory;

    import org.apache.commons.lang3.StringUtils;

    public class OrganismFactory {

    public Organism getOrganism(String type) {
    if (StringUtils.isBlank(type)) {
    return null;
    }
    if (type.equalsIgnoreCase("people")) {
    return new People();
    } else if (type.equalsIgnoreCase("animal")) {
    return new Animal();
    }
    return null;
    }
    }
  4. 完成上述步骤,我们就可以开始演示了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package test.factory;

    public class FactoryDemo {
    public static void main(String[] args) {
    OrganismFactory organismFactory = new OrganismFactory();
    Organism o1 = organismFactory.getOrganism("people");
    o1.say();
    Organism o2 = organismFactory.getOrganism("animal");
    o2.say();
    }
    }

    运行结果:

    1
    2
    people say
    animal say
说明:

优点:1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

享元模式

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。典型的 String str = “abc”;如果有,则返回,如果没有则在字符串常量池中创建。

示例演示:
  1. 我们定义一个生物接口,生物接口中有一个说话的功能。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    package test.flyweight;

    /**
    * 所有生物的标识
    */
    public interface Organism {
    //所有生物共有的一个功能,有自己的沟通方式
    String say();
    }
  2. 定义一个动物实体类,让他具有生物的性质。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package test.flyweight;

    import lombok.Data;

    @Data
    public class Animal implements Organism {

    private String name;

    public Animal(String name) {
    this.name = name;
    }

    @Override
    public String say() {
    return "my name is :" + name;
    }
    }
  3. 创建一个工厂,用来创建和存储animal实体类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package test.flyweight;

    import java.util.HashMap;
    import java.util.Map;

    public class OrganismFactory {
    private final static Map<String, Organism> animalMap = new HashMap<>();

    public static Organism getAnimal(String name) {
    Animal animal = (Animal) animalMap.get(name);
    if (animal == null) {
    animal = new Animal(name);
    animalMap.put(name, animal);
    System.out.println(animal.say()+"第一次创建");
    }else{
    System.out.println(animal.say()+"从池中取出");
    }
    return animal;
    }

    }
  4. 完成上述步骤,我们就可以开始演示了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package test.flyweight;

    public class FlyweightDemo {

    public static void main(String[] args) {
    String[] names = {"a", "b", "c", "d"};
    for (int i = 0; i < 10; i++) {
    OrganismFactory.getAnimal(names[getIndex()]);
    }
    }

    private static Integer getIndex() {
    return (int) (Math.random() * 4);
    }
    }

    运行结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    my name is :d第一次创建
    my name is :d从池中取出
    my name is :a第一次创建
    my name is :b第一次创建
    my name is :c第一次创建
    my name is :c从池中取出
    my name is :c从池中取出
    my name is :c从池中取出
    my name is :a从池中取出
    my name is :d从池中取出
说明:

在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。大大减少对象的创建,降低系统的内存,使效率提高;缺点是提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

我们通过下面的实例来演示装饰器模式的用法。

示例演示
  1. 我们定义一个生物接口,生物接口中有一个说话的功能。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    package test.decorator;

    /**
    * 所有生物的标识
    */
    public interface Organism {
    //所有生物共有的一个功能,有自己的沟通方式
    void say();
    }
  1. 定义一个人类实体类,让他具有生物的性质。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    package test.decorator;

    public class People implements Organism{

    @Override
    public void say() {
    System.out.println("people say");
    }
    }
  1. 接下来,重点来了,我们要对这个生物的接口进行拓展,但是其是一个原始属性的接口,所以我们定义一个抽象类,来装饰这个接口。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package test.decorator;

    public class OrganismDecorator implements Organism {
    protected Organism organism;

    public OrganismDecorator(Organism organism) {
    this.organism = organism;
    }

    public void say() {
    organism.say();
    }

    }
  2. 现在我们再对这个接口进行实际拓展,比如可以说中文,也可以说英文。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package test.decorator;

    public class ChineseOrganismDecorator extends OrganismDecorator{
    public ChineseOrganismDecorator(Organism organism) {
    super(organism);
    }

    @Override
    public void say(){
    organism.say();
    this.language(organism);
    }

    private void language(Organism organism){
    System.out.println("say Chinese");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package test.decorator;

    public class EnglishOrganismDecorator extends OrganismDecorator {
    public EnglishOrganismDecorator(Organism organism) {
    super(organism);
    }

    @Override
    public void say() {
    organism.say();
    this.language(organism);
    }

    private void language(Organism organism) {
    System.out.println("say English");
    }
    }
  3. 完成上面的步骤,我们的接口拓展就完成了,这时候我们演示一下这个接口,让某个人同时可以说中文和英文。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package test.decorator;

    public class DecoratorDemo {
    public static void main(String[] args) {
    Organism people = new People();

    OrganismDecorator speak = new OrganismDecorator(people);

    ChineseOrganismDecorator chinese = new ChineseOrganismDecorator(speak);
    EnglishOrganismDecorator english = new EnglishOrganismDecorator(chinese);
    english.say();

    }
    }

    运行结果:

    1
    2
    3
    people say
    say Chinese
    say English
  1. 我们也可以接着创建一个动物,动物也有自己说话的方式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    package test.decorator;

    public class Animal implements Organism{

    @Override
    public void say() {
    System.out.println("animal say");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package test.decorator;

    public class AnimalOrganismDecorator extends OrganismDecorator {
    public AnimalOrganismDecorator(Organism organism) {
    super(organism);
    }

    @Override
    public void say() {
    organism.say();
    this.language(organism);
    }

    private void language(Organism organism) {
    System.out.println("say animal");
    }
    }
  2. 实例化动物,让其有Organism的属性,但是有自己独特的说话方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    package test.decorator;

    public class DecoratorDemo {
    public static void main(String[] args) {

    Organism animal = new Animal();
    OrganismDecorator animalSpeak = new OrganismDecorator(animal);
    AnimalOrganismDecorator animLan = new AnimalOrganismDecorator(animalSpeak);
    animLan.say();

    }
    }

    运行结果:

    1
    2
    animal say
    say animal
说明

以上就是装饰器模式,这种模式的出现是为了更好的拓展功能,而尽可能的减小原结构的改造,各个类都可以独立发展,互相不耦合;缺点就是随着功能的多样化,子类会变得越来越复杂。

newCachedThreadPool

创建一个可缓存的线程池

如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

示例:

1
2
3
4
5
6
public static ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(new Runnable() {
public void run () {
//TODO
}
});
newFixedThreadPool

创建固定大小的线程池

每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FixedThreadPoolDemo extends Thread {
private int index;

public FixedThreadPoolDemo(int index) {
this.index = index;
}

public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(2);
for (int i = 0; i < 5; i++) {
service.execute(new FixedThreadPoolDemo(i));
}
System.out.println("finish");
service.shutdown();
}

public void run() {
try {
System.out.println(Thread.currentThread().getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果:

1
2
3
4
5
6
finish
pool-1-thread-2
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-2
newSingleThreadExecutor

创建一个单线程的线程池

这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingleThreadPoolDemo extends Thread {
private int index;

public SingleThreadPoolDemo(int index) {
this.index = index;
}

public static void main(String[] args) {
ExecutorService service = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
service.execute(new SingleThreadPoolDemo(i));
}
System.out.println("finish");
service.shutdown();
}

public void run() {
try {
System.out.println(Thread.currentThread().getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果:

1
2
3
4
5
6
finish
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
newScheduledThreadPool

创建一个周期任务线程池

此线程池支持定时以及周期性执行任务的需求

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
package test;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolDemo {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.schedule(() -> System.out.println(Thread.currentThread().getName()), 2, TimeUnit.SECONDS);
}

}

运行结果(该程序表示延迟2s执行):

1
pool-1-thread-1
scheduleAtFixedRate

周期线程中的定时任务

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
package test;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolDemo {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.scheduleAtFixedRate(() -> System.out.println(Thread.currentThread().getName()), 5, 2,TimeUnit.SECONDS);
}

}

运行结果(该程序表示程序启动5s后,每隔2s执行一次):

1
2
3
4
5
6
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
.
.
.
scheduleWithFixedDelay

周期线程中的定时任务

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
package test;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolDemo {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.scheduleWithFixedDelay(() -> System.out.println(Thread.currentThread().getName()), 5, 2,TimeUnit.SECONDS);
}

}

运行结果

1
2
3
4
5
6
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
.
.
.

说明:scheduleAtFixedRate和scheduleWithFixedDelay的区别在于前者是时间间隔过后,再检查任务是否结束,如果结束了,立即执行下个任务,后者是先等待任务结束,然后再等待时间间隔过后再执行。

newSingleThreadScheduledExecutor

定时任务

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
package test;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class SingleThreadScheduledPoolDemo {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(() -> System.out.println(Thread.currentThread().getName()), 5, 2,TimeUnit.SECONDS);
}

}

运行结果(该程序表示程序启动5s后,每隔2s执行一次):

1
2
3
4
5
6
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
.
.
.

ScheduledExecutorService执行的周期任务,如果执行过程中抛出了异常,那么任务就会停止,周期也会停止。