大话设计模式笔记

第一章

面向对象

  • 面向对象的方法:将一个整体分门别类的划分成许多块。如:一篇文章整体修改很麻烦,但活字印刷将一篇文章中的每个字切成一个对象,就可以很好的修改(可维护),重复(可复用)使用以及加入新的字(可扩展)。
  • 面向对象的好处:将一个整体切分成多块后,可以更少成本的维护(由于是改某一小个部件),复用(可将某个或某几个部件进行拼装使用),扩展(分类后,加入新的小类也更加方便)。

简单工厂模式

  • 介绍:工厂将分好的各类进行统一的管理,需要什么类,就返回什么类。(可以基于反射实现)
  • 应用场景:
    • 优势:类的特性相同,且频繁切换类。
    • 劣势:加入新类需要重新编译打包,无法将多个类组合使用的情况。
      这里写图片描述

UML类图

这里写图片描述

第二章 策略模式

  • 介绍:相对于工厂模式,不将具体的类暴露给调用者,而是在工厂中判断需要哪个类,则提供调用该类的方法给调用者。
  • 应用场景:
    • 优势:类的特性相同,且频繁切换类,且只需要用到单一的算法。
      • 劣势:加入新类需要重新编译打包,无法将多个类组合使用的情况。
        这里写图片描述

第三章 单一职责原则

  • 介绍:类的功能尽量单一,也就是活字印刷将文章划分成单一的字,而不是词的原因。
  • 划分原则:应该仅有一个引起它变化的原因。
  • 应用:类的功能设计尽量单一。

第四章 开放-封闭原则

  • 介绍:对修改关闭,对扩展开放。
  • 实现方式:通过接口或抽象类的继承,通过不同子类应对变化。如下图。

这里写图片描述

  • 应用场景:程序容易变化的地方,需求容易产生变更的地方使用接口定义。

第五章

依赖倒转原则

  • 介绍:A:高层模块不应该依赖低层模块。两个都应该依赖抽象。B:抽象不应该依赖细节。细节应该依赖抽象。
  • 应用场景:也就是面向接口和抽象编程。

里式替换原则

  • 介绍:子类型必须能够替换掉他们的父类型。
  • 应用场景:在扩展时,只需要替换即可完成,无需修改其他子类和父类代码。

##第六章 装饰模式

  • 介绍:装饰模式,动态地给一个对象添加一些额外的职责,就功能来说,装饰模式比生成子类更为灵活。
  • 实现方式:通过编写一个抽象类,子类构造方法中传入需要装饰的父类,并实现父类的方法,对其进行装饰。

装饰模式

// 装饰接口
public interface Decorator {
    void operation();
}
// 具体装饰A
class ConcreteDecoratorA implements Decorator{
    private String addedState = "add state";
    private Decorator decorator;

    public ConcreteDecoratorA(Decorator decorator) {
        this.decorator = decorator;
    }


    @Override
    public void operation() {
        // 加入状态装饰
        System.out.println(addedState);
        decorator.operation();
    }
}
// 具体装饰B
class ConcreteDecoratorB implements Decorator{
    private Decorator decorator;

    public ConcreteDecoratorB(Decorator decorator) {
        this.decorator = decorator;
    }

    private void addedBehavior(){
        System.out.println("add Behavior");
    }

    @Override
    public void operation() {
        decorator.operation();
        // 加入行为装饰
        addedBehavior();
    }
}
// 客户端
class Client {
    public static void main(String[] args) {
        // 未加装饰的基础对象
        Decorator decorator = new Decorator() {
            @Override
            public void operation() {
                System.out.println("base operation!!!");
            }
        };
        Decorator decoratorB = new ConcreteDecoratorB(decorator);
        Decorator decoratorA = new ConcreteDecoratorA(decoratorB);
        decoratorA.operation();

    }
}
  • 应用场景:需要对某一个类的方法前后切面上加入新的状态功能或方法的情况,局限在于方法较为固定,且必须实现或继承接口和抽象类。

第七章 代理模式

  • 介绍:代理模式是为其他对象提供一种代理以控制对这个对象的访问,从而可以在不改变原有类的基础上,在这个类的各个方法的前后各切面上加入新增的功能方法。
  • 实现方式:
    • 普通代理:创建一个中间对象,将需要代理的对象进行注入,并在其方法上加入新增功能。
// 代理
public class NoamalProxy {
    private PersonDao personDao;
    private Trancation trancation;

    public NoamalProxy(PersonDao personDao, Trancation trancation) {
        this.personDao = personDao;
        this.trancation = trancation;
    }

    public void savePerson() {
        // 开启事务
        trancation.beginTrancation();
        // 保存人员
        personDao.savePerson();
        // 提交事务
        trancation.commit();
    }
}
// 人员DAO
class PersonDao {
    public void savePerson() {
        System.out.println("保存人员");
    }
}
// 事务
class Trancation {
    public void beginTrancation() {
        System.out.println("开启事务");
    }

    public void commit() {
        System.out.println("提交事务");
    }
}
// 客户端
class Client {
    public static void main(String[] args) {
        NoamalProxy proxy = new NoamalProxy(new PersonDao(),new Trancation());
        proxy.savePerson();
    }
}
- jdk代理:创建一个接口和一个实现类,以及一个实现了InvocationHandler的实现类,重写invoke方法,则在代理对象调用时,会调用该方法。
// jdk代理
public class JdkProxy implements InvocationHandler{
    private Trancation2 trancation;
    private PersonDao2 target;

    public JdkProxy(Trancation2 trancation, PersonDao2 target) {
        this.trancation = trancation;
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 开启事务
        trancation.beginTrancation();
        // 方法调用,注!!!此处传入的Object为代理,而不是目标类,目标类需要另外注入
        Object obj = method.invoke(target, args);
        // 开启事务
        trancation.commit();
        return obj;
    }
}
// jdk的代理需要实现接口
interface  PersonDao2{
    void savePerson();
}
// 人员DAO
class PersonDaoImpl2 implements PersonDao2{
    @Override
    public void savePerson() {
        System.out.println("保存人员");
    }
}
// 事务
class Trancation2 {
    public void beginTrancation() {
        System.out.println("开启事务");
    }

    public void commit() {
        System.out.println("提交事务");
    }
}
// 客户端
class Client2 {
    public static void main(String[] args) {
        Trancation2 t2 = new Trancation2();
        PersonDao2 p2 = new PersonDaoImpl2();
        JdkProxy jdkProxy = new JdkProxy(t2,p2);
        PersonDao2 dao2 = (PersonDao2) Proxy.newProxyInstance(p2.getClass().getClassLoader(),p2.getClass().getInterfaces(),jdkProxy);
        dao2.savePerson();
    }
}
- cglib代理:创建一个类,以及一个实现了MethodInterceptor的实现类,重写intercept方法,则在代理对象调用时,会调用该方法,并初始化Enhancer类,该对象可创建代理对象。
// cglib代理
public class CglibProxy implements MethodInterceptor{
    private Trancation3 trancation;
    private PersonDao3 target;
    
    public CglibProxy(Trancation3 trancation, PersonDao3 target) {
        this.trancation = trancation;
        this.target = target;
    }
    // 创建代理
    public Object createProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        // 开启事务
        trancation.beginTrancation();
        // 方法调用,注!!!此处传入的Object为代理,而不是目标类,目标类需要另外注入
        Object obj = method.invoke(target, objects);
        // 提交事务
        trancation.commit();
        return obj;
    }
}
// 人员DAO
class PersonDao3 implements PersonDao2{
    @Override
    public void savePerson() {
        System.out.println("保存人员");
    }
}
// 事务
class Trancation3 {
    public void beginTrancation() {
        System.out.println("开启事务");
    }

    public void commit() {
        System.out.println("提交事务");
    }
}
// 客户端
class Client3 {
    public static void main(String[] args) {
        Trancation3 t3 = new Trancation3();
        PersonDao3 p3 = new PersonDao3();
        CglibProxy cglibProxy = new CglibProxy(t3,p3);
        PersonDao3 personDao3 = (PersonDao3) cglibProxy.createProxy();
        personDao3.savePerson();
    }
}
  • 应用场景:需要统一对各个类的方法切面上新增操作时,如加入日志,权限校验等。

第八章 工厂模式

  • 介绍:工厂模式为用户在切换使用对象时可通过配置文件加反射的方式,选择需要创建的对象。
  • 实现方式:创建工厂接口和对象的工厂类,创建具体类和抽象类,通过工厂类进行初始化。其中对工厂的抽象化是为了在客户端可以方便地扩展工厂。
// 工厂接口  
public interface Factory {
    Animal createAnimal();
}
// 动物抽象类
abstract class Animal{
    abstract void eat();
}
// 狗
class Dog extends Animal{
    @Override
    void eat() {
        System.out.println("狗啃骨头");
    }
}
// 猫
class Cat extends Animal{
    @Override
    void eat() {
        System.out.println("猫吃鱼");
    }
}
// 狗工厂
class DogFactory implements Factory{

    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}
// 猫工厂
class CatFactory implements Factory{

    @Override
    public Animal createAnimal() {
        return new Cat();
    }
}
// 客户端
class Client{
    public static void main(String[] args) {
        Factory catFactory = new CatFactory();
        Animal cat = catFactory.createAnimal();
        Factory dogFactory = new DogFactory();
        Animal dog = dogFactory.createAnimal();
        cat.eat();
        dog.eat();
    }
}
  • 应用场景:创建使用的对象需要频繁更换时。

第九章 原型模式——深浅复制

-介绍:实际就是对对象数据的复制,浅复制指只对对象的基本类型复制,引用类型只复制引用,而深复制会把引用类型的数据进行复制;

-实现方式:通过在实体上实现Cloneable接口,并重写clone()方法进行实现。代码如下:

public class CloneTest implements Cloneable {

    private String name;
    private City city;

    @Override
    public CloneTest clone() {
        CloneTest cloneTest = null;
        try {
            // 浅复制——只复制该对象的基本类型数据
            cloneTest = (CloneTest) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        // 对引用的数据进行复制为深度复制
        cloneTest.city = city.clone();
        return cloneTest;
    }
}
  • 应用场景:需要用到对象的大部分数据,并进行小部分修改,又不想影响原有对象的情况。
  • 注意:
    1. clone()方法不依赖于get/set方法;
      2. 实体不实现Cloneable接口的情况下,调用父类的clone()方法,会报CloneNotSupportedException的异常;

第十章 模板设计模式

  • 介绍:模板设计模式是提供一个顶级的逻辑骨架,逻辑中具体的步骤在抽象方法中,推迟到子类实现。从而能够将大部分相同的逻辑抽象到父类方法中,具体小的细节由子类进行实现。
  • 实现方式:在父类中定义一个具体方法,该方法调用该类的抽象方法,由子类实现具体的抽象方法,最后调用该类的具体方法。如下图:
    模板模式结构图
public abstract class TestTemplate {

    public void templateMethod() {
        System.out.println("我需要获取person表中的数据");
         selectPerson();
    }

    public abstract void selectPerson();

    public static void main(String[] args) {
        TestTemplate testTemplate = new TestTemplate() {
            @Override
            public void selectPerson() {
                System.out.println("通过postgresql数据库获取person数据 name:'sean' age:12");
            }
        };
        testTemplate.templateMethod();
    }
}

  • 应用场景:一个方法中的大部分逻辑相同,只有一部分方法逻辑不同需要进行抽象。

第十一章 迪米特法则

  • 介绍:通过统一的接口(人),对类之间的调用进行解耦操作。
  • 实现方式:两个类之间不必彼此直接通信时,两个类可通过第三者转发这个调用。

第十二章 外观模式

  • 介绍:是对多个类的复杂逻辑的同一封装,也就是上述迪米特法则的统一实现。

  • 实现方式:在一个类中将复制的逻辑进行封装,提供统一的接口方法,最常见的就是三层架构中的service接口,如下图:
    外观模式

  • 应用场景:存在复杂的下层逻辑和多个下层对象,但上层可整理出规范的接口。

第十三章 建造者模式

  • 介绍:该模式与模板模式类似,都是提供一个逻辑的骨架,而骨架中的具体实现则交由实现类完成,与模板模式的区别在于将构建过程从模板类中移至指挥类中,从而使得建造者类可以没有具体方法,成为接口。
  • 实现方式:见下图和代码。

建造者模式

//建造者接口
public interface Builder {
    // 添加第一部分
    void addPart1();
    // 添加第二部分
    void addPart2();
    // 获得产品
    Product getProduct();
}

// 产品
class Product {
    private List<String> parts = new ArrayList<>();
    // 添加部分
    public void add(String s) {
        parts.add(s);
    }
    // 展示产品
    public void show() {
        System.out.println(parts);
    }
}

// 指挥者
class Director {
    public void construct(Builder builder) {
        builder.addPart1();
        builder.addPart2();
    }

    public static void main(String[] args) {
        Director director = new Director();
        // 创建具体的构造者
        Builder b1 = new Builder() {
            private Product product = new Product();

            @Override
            public void addPart1() {
                product.add("X");
            }

            @Override
            public void addPart2() {
                product.add("Y");
            }

            @Override
            public Product getProduct() {
                return product;
            }
        };
        director.construct(b1);
        // 创建具体的构造者
        Builder b2 = new Builder() {
            private Product product = new Product();

            @Override
            public void addPart1() {
                product.add("A");
            }

            @Override
            public void addPart2() {
                product.add("B");
            }

            @Override
            public Product getProduct() {
                return product;
            }
        };
        director.construct(b2);
        Product product1 = b1.getProduct();
        Product product2 = b2.getProduct();
        product1.show();
        product2.show();
    }
}

  • 应用场景:对具体的构建过程的抽象。

第十四章 观察者模式

  • 介绍:一个事件产生后,需要得知此事件的对象都需要进行相应的相应的过程。
  • 实现方式:实际是对事件和监听者之间的解耦。
    1. 事件属性中直接加入观察者对象,事件产生后,调用观察者的统一接口方法;
// 事件
public class Event1 {
    private List<Listenser> listensers = new ArrayList<>();

    public void addListenser(Listenser listenser) {
        listensers.add(listenser);
    }

    public void handEvent() {
        for (Listenser listenser : listensers) {
            if (listenser == null) {
                continue;
            }
            listenser.onEvent();
        }
    }
}

interface Listenser {
    void onEvent();
}
// 监听器A
class ListenserA implements Listenser {

    @Override
    public void onEvent() {
        System.out.println("listenser A!");
    }
}
// 监听器B
class ListenserB implements Listenser {

    @Override
    public void onEvent() {
        System.out.println("listenser B!");
    }
}
// 客户端
class Client{
    public static void main(String[] args) {
        Listenser la = new ListenserA();
        Listenser lb = new ListenserB();
        Event1 event = new Event1();
        event.addListenser(la);
        event.addListenser(lb);
        event.handEvent();
    }
}

2. 事件属性中加入一个观察者对象,其中包括观察者对象,观察者需要调用的方法名和方法的参数数组;

public class Event2 {
    private List<ListenserDto> listenserDtos = new ArrayList<>();

    public void addListenser(ListenserDto listenserDto) {
        listenserDtos.add(listenserDto);
    }

    public void handEvent() {
        if (listenserDtos != null && listenserDtos.size() > 0) {
            for (ListenserDto listenserDto : listenserDtos) {
                if (listenserDto == null) {
                    continue;
                }
                try {
                    // 通过反射调用方法
                    Method method = listenserDto.getObj().getClass().getMethod(listenserDto.getMethodNamd(), listenserDto.getArgTypes());
                    method.invoke(listenserDto.getObj(), listenserDto.getArgs());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
// 监听对象方法及参数的DTO
class ListenserDto {
    private Object obj;
    private String methodNamd;
    private Object[] args;
    private Class[] argTypes;

    public Object getObj() {
        return obj;
    }

    public String getMethodNamd() {
        return methodNamd;
    }

    public Object[] getArgs() {
        return args;
    }

    public Class[] getArgTypes() {
        return argTypes;
    }

    public ListenserDto(Object obj, String methodNamd, Object[] args) {
        this.obj = obj;
        this.methodNamd = methodNamd;
        this.args = args;
        if (args != null && args.length > 0) {
            this.argTypes = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                argTypes[i] = args[i].getClass();
            }
        }
    }
}

class Listenser2A {
    public void methodA(String name, Integer age) {
        System.out.println("A " + name + " -- " + age);
    }
}

class Listenser2B {
    public void methodB(String name) {
        System.out.println("B " + name);
    }
}

class Client2 {
    public static void main(String[] args) {
        Event2 event2 = new Event2();
        // 将监听者及方法和参数放入事件中
        event2.addListenser(new ListenserDto(new Listenser2A(),"methodA",new Object[]{"sean",22}));
        event2.addListenser(new ListenserDto(new Listenser2B(),"methodB",new Object[]{"tan"}));
        event2.handEvent();
    }
}

3. 事件的构造方法中加入观察者的接口类型,在调用事件发布方法时,遍历观察者接口的所有容器中的实体,并调用统一的接口方法;

@Component
public class Event3 {
    private Class listenserClass;

    public Event3() {
        this.listenserClass = Listenser3.class;
    }

    public void sendNotify(){
        // 通过类型获取容器中的监听者,进行方法调用
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Map beansMap = context.getBeansOfType(listenserClass);
        Collection beans = beansMap.values();
        if (beans != null && beans.size() > 0) {
            for (Object bean : beans) {
                Listenser3 li = (Listenser3)bean;
                li.onEvent(this);
            }
        }
    }
}

interface Listenser3{
    void onEvent(Event3 event3);
}

@Service
class Listenser3A implements Listenser3{

    @Override
    public void onEvent(Event3 event3) {
        System.out.println("listenser3A "+event3);
    }
}

@Service
class Listenser3B implements Listenser3{

    @Override
    public void onEvent(Event3 event3) {
        System.out.println("listenser3B "+event3);
    }
}

class Client{
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Event3 event3 = (Event3) context.getBean("event3");
        event3.sendNotify();
    }
}

4. 通过spring实现,观察者中加入事件的泛型,在调用事件发布方法时,通过含有泛型的观察者接口的所有容器中的实体,并调用统一的接口方法;

@Component
public class Event4 extends ApplicationEvent{
    public Event4(){
        super("ss");
    }

    public Event4(Object source) {
        super(source);
    }

    public void sendNotify(){
        // 通过容器发布事件,实际会根据监听者的泛型找到监听者,并调用onApplicationEvent方法
        new ClassPathXmlApplicationContext("applicationContext.xml").publishEvent(this);
    }
}

@Component
class Listenser4A implements ApplicationListener<Event4> {

    @Override
    public void onApplicationEvent(Event4 event4) {
        System.out.println("Listenser4A " +event4);
    }
}

class Client4{
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Event4 event4 = (Event4) context.getBean("event4");
        event4.sendNotify();
    }
}

  • 应用场景:两个组件间没有必要的关联和依赖,但其中一个组件需要监听另一个组件的数据变化。

第十五章 抽象工厂模式

  • 介绍:用户需要什么,工厂就生成创建什么,解除了客户端对具体对象的依赖,而交由工厂中的反射获取配置文件中具体需要哪种类型。
  • 实现方式:创建一个工厂,由工厂根据配置调用反射创建需要创建的对象,在客户端调用该工厂获取需要的对象即可:
// 数据库工厂
public class DBFactory {
    // 此处可通过配置文件读取
    private static String dbName = "MySql";
    public static DB createDB(){
        try {
            // 通过反射进行解耦,创建实体
            return (DB) Class.forName("com.sean.design.a14_factory."+dbName + "DB").newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

// 数据库
interface DB{
    void save();
}

// MySql数据库
class MySqlDB implements DB{

    @Override
    public void save() {
        System.out.println("MySql save");
    }
}

// Postgresql数据库
class PostgresqlDB implements DB{

    @Override
    public void save() {
        System.out.println("Postgresql save");
    }
}

class Client{
    public static void main(String[] args) {
        DB db = DBFactory.createDB();
        db.save();
    }
}

  • 应用场景:需要对使用的对象进行多态的切换时,可用该设计模式。

第十六章 状态模式

  • 介绍:为了消除庞大的条件分支语句,通过把各种状态转移逻辑分布到 State 的子类之间,来减少相互间的依赖。
  • 实现方式:通过一个Context来调用 State 状态的处理方法,而 State 状态的处理方法中除了状态的处理方法外,还有根据条件进行状态切换的逻辑。

状态设计模式

public class Context {
    private State state;

    public Context(State state) {
        this.state = state;
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }
    // 逻辑处理
    public void request(){
        state.handle(this);
    }
}
// 状态接口
interface State{
    void handle(Context context);
}
// 具体状态A
class StateA implements State{

    @Override
    public void handle(Context context) {
        // 逻辑处理
        System.out.println("this is state A");
        // 状态切换
        context.setState(new StateB());
    }
}
// 具体状态B
class StateB implements State{

    @Override
    public void handle(Context context) {
        // 逻辑处理
        System.out.println("this is state B");
        // 状态切换
        context.setState(new StateA());
    }
}

class client{
    public static void main(String[] args) {
        Context context = new Context(new StateA());
        context.request();
        context.request();
        context.request();
    }
}

  • 应用场景:主要用于判断逻辑较多,状态较多,且随着状态变化会引发其他逻辑调用的情况。

第十七章 适配器模式

  • 介绍:适配器模式主要作用是对已经无法改变或难以改变的接口进行再次包装,以便调用进行适配。
  • 实现方式:在需要适配的接口上再加上一层接口进行包装。

适配器模式

// 适配器
public class Adapter implements MyTarget{
    private NeedAdapter needAdapter = new NeedAdapter();

    @Override
    public void test3(){
        needAdapter.test1();
    }
}
// 统一的接口
interface MyTarget{
    void test3();
}
// 需要适配的类
class NeedAdapter{
    public void test1(){
        System.out.println("test1");
    }

    public void test2(){
        System.out.println("test2");
    }
}
// 客户端
class Client{
    public static void main(String[] args) {
        MyTarget target = new Adapter();
        target.test3();
    }
}

  • 应用场景:在无法改变或难以改变的接口因却需要进行兼容时,加入适配器。

第十八章 备忘录模式

  • 介绍:备忘录模式更像一种场景,需要备份一个对象的模式,用对象本身克隆存在有不需要备份的字段也会备份,不够灵活的问题。而备忘录模式是将数据备份的读和写交由第三方来实现,更加灵活,解耦。
  • 实现方式:将本对象的值交由另一备忘录对象存储管理,本对象只需要实现获取备忘录对象和恢复备忘录对象的值,而具体需要备份和恢复哪些值则交由备忘录对象来决定,从而进行解耦。
public class GamePlayer {
    private String name;// 姓名
    private int attack;// 攻击力
    private int defense;// 防御力
    // 创建备忘录
    public Memo getMemo(){
        return new Memo(this);
    }
    // 还原备忘录
    public void recoverMemo(Memo memo){
        memo.recover(this);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAttack() {
        return attack;
    }

    public void setAttack(int attack) {
        this.attack = attack;
    }

    public int getDefense() {
        return defense;
    }

    public void setDefense(int defense) {
        this.defense = defense;
    }

    @Override
    public String toString() {
        return "GamePlayer{" +
                "name='" + name + '\'' +
                ", attack=" + attack +
                ", defense=" + defense +
                '}';
    }
}
// 备忘录
class Memo{
    private int attack;
    private int defense;

    // 创建备忘录
    public Memo(GamePlayer gamePlayer){
        this.attack = gamePlayer.getAttack();
        this.defense = gamePlayer.getDefense();
    }

    // 恢复备忘录
    public void recover(GamePlayer gamePlayer) {
        gamePlayer.setAttack(this.attack);
        gamePlayer.setDefense(this.defense);
    }
}
class Client{
    public static void main(String[] args) {
        GamePlayer gamePlayer = new GamePlayer();
        gamePlayer.setName("Sean");
        gamePlayer.setAttack(100);
        gamePlayer.setDefense(100);
        System.out.println("战斗前");
        System.out.println(gamePlayer);
        Memo memo = gamePlayer.getMemo();
        gamePlayer.setDefense(80);
        gamePlayer.setAttack(70);
        System.out.println("战斗后");
        System.out.println(gamePlayer);
        System.out.println("恢复到战斗前");
        gamePlayer.recoverMemo(memo);
        System.out.println(gamePlayer);
    }
}

  • 应用场景:数据需要进行备份存储的场景。

第十九章 组合模式

  • 介绍:组合模式不像一种设计模式,更像是一种数据结构,有顶级节点,并在节点下挂有下级节点对象的一棵树,每个节点有各自的方法,且可以执行含本级节点及下级节点信息的操作。
  • 实现方式:定义一个抽象类,然后定义一个继承抽象类的具体类,该具体类有一个抽象类的集合作为分支节点。

组合模式

public abstract class Company {
    private String name;
    // 加入
    abstract void addCompany(Company company);

    abstract void removeCompany(Company company);
    // 打印所有分公司部门
    abstract void printLine(int depth);
    // 履行职责
    abstract void lineOfDuty();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
// 分公司
class ConcreteCompany extends Company{

    private List<Company> companies = new ArrayList<>();

    @Override
    void addCompany(Company company) {
        companies.add(company);
    }

    @Override
    void removeCompany(Company company) {
        companies.remove(company);
    }

    @Override
    void printLine(int depth) {
        for (int i = 0;i<depth;i++){
            System.out.print("-");
        }
        System.out.println(this.getName());
        if (companies != null && companies.size() > 0) {
            for (Company company : companies) {
                if (company == null) {
                    continue;
                }
                company.printLine(depth+2);
            }
        }
    }

    @Override
    void lineOfDuty() {
        if (companies != null && companies.size() > 0) {
            for (Company company : companies) {
                if (company == null) {
                    continue;
                }
                company.lineOfDuty();
            }
        }
    }
}
// HR部门
class HRDepartment extends Company{

    @Override
    void addCompany(Company company) {}

    @Override
    void removeCompany(Company company) {}

    @Override
    void printLine(int depth) {
        for (int i = 0;i<depth;i++){
            System.out.print("-");
        }
        System.out.println(this.getName());
    }

    @Override
    void lineOfDuty() {
        System.out.println(this.getName()+"负责招聘");
    }
}

class Client{
    public static void main(String[] args) {
        Company root = new ConcreteCompany();
        root.setName("北京总公司");
        HRDepartment rootDepartment = new HRDepartment();
        rootDepartment.setName("北京HR部门");
        root.addCompany(rootDepartment);
        Company hangZhou = new ConcreteCompany();
        hangZhou.setName("杭州分公司");
        HRDepartment hangZhouDepartment = new HRDepartment();
        hangZhouDepartment.setName("杭州HR部门");
        hangZhou.addCompany(hangZhouDepartment);
        root.addCompany(hangZhou);
        Company nanJing = new ConcreteCompany();
        nanJing.setName("南京分公司");
        root.addCompany(nanJing);
        root.printLine(1);
        System.out.println();
        root.lineOfDuty();
    }
}

  • 应用场景:主要应有于需要体现部分与整体层次结构时,并能够忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象。

第二十章 迭代器模式

由于java通过增强for实现该模式,故略。

第二十一章 单例模式

  • 介绍:单例模式也就是一个类有且只有一个实例对象,故需要对其构造方法私有化,且实例的初始化由本类进行,初始化时机的不同使单例模式分为懒汉式(在调用获取实例的静态方法中初始化)和饿汉式(在类加载时,通过静态变量进行初始化)。
  • 实现方式:1.构造方法私有化;2.1在调用获取实例的静态方法中初始化,此处需要进行加锁,因为多线程情况会导致多实例化;2.2在类加载时,通过静态变量进行初始化

单例模式

// 懒汉式,在获取实例时初始化,通过加锁避免多线程问题,消耗加锁的时间,但节约内存开销,只有在需要用到该实例时才初始化
public class LazySingleton {
    private static volatile LazySingleton lazySingleton;// volatile关键字是防止指令重排,防止初始化实例中的创建对象和设置引用重排,导致另一线程判断非空时直接返回
    private LazySingleton() {
    }

    public static LazySingleton getInstance(){
        // 不在每次获取实例时加锁,节约资源
        if (lazySingleton==null){
            synchronized (LazySingleton.class){
                // 可能在获取锁前已经由另一线程初始化
                if (lazySingleton == null){
                    return new LazySingleton();
                }
            }
        }
        return lazySingleton;
    }
}
// 饿汉式,在类加载时初始化,消耗内存,但避免多线程问题
class EagerSingleton{
    private static EagerSingleton eagerSingleton = new EagerSingleton();
    private EagerSingleton() {
    }
    
    public static EagerSingleton getInstance(){
        return eagerSingleton;
    }
}

  • 应用场景:只需用到一个对象,而无需多对象存在的情况,例如三层架构中的service和core层。

第二十二章 桥接模式

  • 介绍:桥接模式主要是基于合成/聚合复用原则(尽量使用合成/聚合,尽量不要使用集成)实现的,他将不是is a 的继承关系拆分成 has a 的关系,从而解除了强耦合,当有一个(has a)新特性时,不需要改每个实现类,只需要加一个聚合的类即可。
  • 实现方式:将没有继承关系的类拆分成合成/聚合的关系,当有新功能时,只需要加一个合成或聚合的类即可。

桥接模式

// 抽象类
public abstract class Abstraction {
    // 通过聚合关系进行桥接
    private Implementor implementor;
    // 操作桥接对象的功能方法
    abstract void operation();

    public Implementor getImplementor() {
        return implementor;
    }

    public void setImplementor(Implementor implementor) {
        this.implementor = implementor;
    }
}
// 具体类
class RefinedAbstraction extends Abstraction{

    @Override
    void operation() {
        this.getImplementor().operationImpl();
    }
}
// 桥接抽象类
abstract class Implementor{
    // 桥接类的操作
    abstract void operationImpl();
}
// 具体桥接类A
class ConcreteImplementorA extends Implementor{

    @Override
    void operationImpl() {
        System.out.println("A操作");
    }
}
// 具体桥接类B
class ConcreteImplementorB extends Implementor{

    @Override
    void operationImpl() {
        System.out.println("B操作");
    }
}
// 客户端
class Client{
    public static void main(String[] args) {
        Abstraction abstraction = new RefinedAbstraction();
        abstraction.setImplementor(new ConcreteImplementorA());
        abstraction.operation();
        abstraction.setImplementor(new ConcreteImplementorB());
        abstraction.operation();
    }
}

  • 应用场景:1.关系非继承,而是合成聚合的关系时,可用该模式;2.系统是多角度的分类,每一种分类都有可能变化,可以把多角度分离出来让它们独立变化,减少它们之间的耦合的情况;

第二十三章 命令模式

  • 介绍:命令模式主要是将两个对象间的调用请求抽象成一个命令对象,从而可以对一个请求命令进行操作,如明日记入日志,否决,撤销重做,统一执行,并对调用者和接受者之间解耦,有新的命令,只需增加一个新的类即可,此处与上一个桥接模式类似,也是通过聚合的方式进行解耦。
  • 实现方式:将一个请求进行抽象化成一个类。
    命令模式
// 命令接口
public interface Commond {
    // 获取命令名称
    String getName();
    // 执行命令
     void excute();
}
// 烤羊肉串命令
class BakeMuttonCommond implements Commond{
    private Barbecuer barbecuer;
    private String name = "烤羊肉串";

    @Override
    public String getName() {
        return name;
    }

    public BakeMuttonCommond(Barbecuer barbecuer) {
        this.barbecuer = barbecuer;
    }

    @Override
    public void excute() {
        barbecuer.bakeMutton();
    }
}
// 烤鸡翅命令
class BakeChickenWingCommond implements Commond{
    private Barbecuer barbecuer;
    private String name = "烤鸡翅";

    @Override
    public String getName() {
        return name;
    }

    public BakeChickenWingCommond(Barbecuer barbecuer) {
        this.barbecuer = barbecuer;
    }

    @Override
    public void excute() {
        barbecuer.bakeChickenWing();
    }
}
// 烧烤师傅
class Barbecuer{
    // 烤羊肉串方法
    public void bakeMutton(){
        System.out.println("烤羊肉串!");
    }
    // 烤鸡翅方法
    public void bakeChickenWing(){
        System.out.println("烤鸡翅!");
    }
}
// 服务员
class Water{
    private List<Commond> orders = new ArrayList<>();
    // 增加订单
    public void addOrder(Commond commond){
        if (commond instanceof BakeChickenWingCommond){
            System.out.println("鸡翅没有了,请点别的烧烤。");
        }else {
            orders.add(commond);
            System.out.println("增加订单:"+commond.getName()+" 时间:"+new Date());
        }
    }
    // 取消订单
    public void concleOrder(Commond commond){
        orders.remove(commond);
        System.out.println("取消订单:"+commond.getName()+" 时间:"+new Date());
    }
    // 执行所有命令
    public void notifyCommond(){
        if (orders != null && orders.size() > 0) {
            for (Commond order : orders) {
                if (order == null) {
                    continue;
                }
                order.excute();
            }
        }
    }
}
// 客户端
class Client{
    public static void main(String[] args) {
        Barbecuer barbecuer = new Barbecuer();
        Commond commond1 = new BakeMuttonCommond(barbecuer);
        Commond commond2 = new BakeMuttonCommond(barbecuer);
        Commond commond3 = new BakeMuttonCommond(barbecuer);
        Commond commond4 = new BakeChickenWingCommond(barbecuer);
        Water water = new Water();
        water.addOrder(commond1);
        water.addOrder(commond2);
        water.addOrder(commond3);
        water.addOrder(commond4);
        water.concleOrder(commond1);
        water.notifyCommond();
    }

}

  • 应用场景:主要应用与需要对请求命令进行复杂的操作时,需要将其作为一个类进行抽离。

第二十四章 职责链模式

  • 介绍:职责链模式与之前的状态模式相似,都是将繁琐的条件判断语句化繁为简,抽象成一个对象,然后交由对象根据自身的职权来执行任务,或者切换到下一对象,不同之处在于职责链模式通过设置下一职责链对象,将对象间的切换交由客户端来给出,来进行切换。
  • 实现方式:将繁琐的条件判断语句抽象成对象,由对象来进行条件判断是否能够执行该任务还是切换到下一对象进行任务执行。

职责链模式

// 处理接口
public abstract class Handler {
    protected Handler successor;
    // 设置继任者
    public void setSuccessor(Handler handler) {
        this.successor = handler;
    }
    // 处理请求
    abstract void handleRequest(int request);
}
// 具体处理类A
class ConcreteHandlerA extends Handler {

    @Override
    public void handleRequest(int request) {
        if (request<10){
            System.out.println("ConcreteHandlerA 处理了 "+request+" 该请求");
        }else {
            // 本处理类无权限,则交由继任者处理该请求
            successor.handleRequest(request);
        }
    }
}
// 具体处理类B
class ConcreteHandlerB extends Handler {

    @Override
    public void handleRequest(int request) {
        if (request>=10&&request<20){
            System.out.println("ConcreteHandlerB 处理了 "+request+" 该请求");
        }else {
            // 本处理类无权限,则交由继任者处理该请求
            successor.handleRequest(request);
        }
    }
}
// 具体处理类C
class ConcreteHandlerC extends Handler {

    @Override
    public void handleRequest(int request) {
        System.out.println("ConcreteHandlerC 处理了 " + request + " 该请求");
    }
}
// 客户端
class Client{
    public static void main(String[] args) {
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();
        Handler handlerC = new ConcreteHandlerC();
        handlerA.setSuccessor(handlerB);
        handlerB.setSuccessor(handlerC);
        handlerA.handleRequest(3);
        handlerA.handleRequest(12);
        handlerA.handleRequest(33);
        handlerA.handleRequest(25);
        handlerA.handleRequest(100);
        handlerA.handleRequest(-3);
    }
}

  • 应用场景:存在大片繁琐的条件判断语句时。

第二十五章 中介者模式

  • 介绍:中介者模式是将多个对象间的调用进行抽象成一个中介者,由中介者来控制调用对象的调用,对多个对象间的耦合关系进行解耦,但是对象较多的情况,中介者将会与多个对象进行耦合并变得复杂,尤其是对象调用间没有具体的规律的情况,在中介者中还需要增加何种情况才调用的逻辑判断,较为复杂,若没有该逻辑判断,则与职责链模式类似,故慎用或不用
  • 实现方式:将多个对象间的调用抽象出一个中介者,进行对象间信息交互的中间者。

中介者模式

  • 应用场景:一般用于一组对象以定义良好但是复杂的方式进行通信的场合或者想定制一个分部在多个类中的行为。

第二十六章 享元模式

  • 介绍:享元模式可以避免大量非常相似的类的开销,实际是在对象可以共用的情况下只提供一个对象,从而减少大量实例化对象。
  • 实现方式:将大量有重复使用的对象通过工厂类初始化,并只能获取一个对象。

享元模式

// 享元接口
public abstract class Flyweight {
    protected String name;

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

    // 操作方法
    abstract void operation(int i);
}
// 共享的具体享元
class ConcreteFlyweight extends Flyweight {

    public ConcreteFlyweight(String name) {
        super(name);
    }

    @Override
    public void operation(int i) {
        System.out.println("具体的 "+name+" flyweight:"+i);
    }
}
// 不共享的具体享元
class UnsharedConcreteFlyweight extends Flyweight{

    public UnsharedConcreteFlyweight(String name) {
        super(name);
    }

    @Override
    public void operation(int i) {
        System.out.println("具体的 "+name+" unsharedFlyweight:"+i);
    }
}
// 享元工厂类
class FlyweightFactory{
    private Map<String,Flyweight> flyweights = new HashMap<>();
    // 获取共享单元
    public Flyweight getFlyweights(String name){
        // 若不存在,则创建该享元
        if (!flyweights.containsKey(name)){
            flyweights.put(name, new ConcreteFlyweight(name));
        }
        return flyweights.get(name);
    }
}
// 客户端
class Client{
    public static void main(String[] args) {
        int count = 10;
        FlyweightFactory flyweightFactory = new FlyweightFactory();
        Flyweight x = flyweightFactory.getFlyweights("X");
        x.operation(--count);
        Flyweight y = flyweightFactory.getFlyweights("Y");
        y.operation(--count);
        Flyweight z = flyweightFactory.getFlyweights("Z");
        z.operation(--count);
        Flyweight t = new UnsharedConcreteFlyweight("T");
        t.operation(--count);
    }
}

  • 应用场景:在使用了存储开销很大且重复的对象时考虑使用,且对象的大多数状态可以外部化,如果删除对象的外部状态,可以用相对较少的共享对象取代很多对象时,可以考虑使用享元模式,但享元模式需要一个记录了系统的享元列表,即工厂类中的列表,此处会消耗资源。

第二十七章 解释器模式

  • 介绍:解释器模式的作用主要是对内容进行翻译,通过多个具体类对各类文法进行翻译,从而实现整篇内容得到翻译。
  • 实现方式:通过定义一个抽象类,对需要翻译的文本内容进行接收,并翻译。

解释器模式

  • 应用场景:在需要进行翻译解释转换的场景下进行。

第二十八章 访问者模式

  • 介绍:访问者模式是解决当对象种类固定,操作可扩展的情况,因操作可扩展,所以将操作进行分类,并使用继承或接口,操作类中的方法是区分对象种类的方法实现,若在操作类中的方法需要获取对象种类的数据,则参数中需要传入对象种类的参数。
  • 实现方式:定义一个对象类的接口和具体类及方法,方法为接受操作类,并根据自身调用操作类中的方法,定义一个操作接口和具体类和方法。
    访问者模式
// 人接口
public interface Person {

    String getType();
    // 接受操作
    void accept(Action action);
}
// 操作接口
interface Action {

    String getType();
    // 做男人的操作
    void doManAction(Person person);
    // 做女人的操作
    void doWomanAction(Person person);
}
// 男人
class Man implements Person {

    @Override
    public String getType() {
        return "男人";
    }

    @Override
    public void accept(Action action) {
        action.doManAction(this);
    }
}
// 女人
class Woman implements Person {
    @Override
    public String getType() {
        return "女人";
    }

    @Override
    public void accept(Action action) {
        action.doWomanAction(this);
    }
}
// 成功
class Success implements Action {

    @Override
    public String getType() {
        return "成功";
    }

    @Override
    public void doManAction(Person person) {
        System.out.println(person.getType() + this.getType() + "时,背后多半有一个伟大的女人");
    }

    @Override
    public void doWomanAction(Person person) {
        System.out.println(person.getType() + this.getType() + "时,背后大多有一个不成功的男人");
    }
}
// 失败
class Failing implements Action {
    @Override
    public String getType() {
        return "失败";
    }

    @Override
    public void doManAction(Person person) {
        System.out.println(person.getType() + this.getType() + "时,闷头喝酒,谁也不用劝");
    }

    @Override
    public void doWomanAction(Person person) {
        System.out.println(person.getType() + this.getType() + "时,泪眼汪汪,谁也劝不了");
    }
}
// 结构
class ObjectStruct {
    private List<Person> people = new ArrayList<>();

    public void addPerson(Person person) {
        people.add(person);
    }
    // 遍历循环调用
    public void doAction(Action action) {
        for (Person person : people) {
            if (person == null) {
                continue;
            }
            person.accept(action);
        }
    }
}
// 客户端
class Client {
    public static void main(String[] args) {
        Person man = new Man();
        Person woman = new Woman();
        ObjectStruct os = new ObjectStruct();
        os.addPerson(man);
        os.addPerson(woman);
        os.doAction(new Success());
        os.doAction(new Failing());
    }
}

  • 应用场景:具体类有限且固定,操作无限的情况,容易扩展操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值