设计模式

一、面向对象的七大设计原则

1、开闭原则:软件实体应该对扩展开放,对修改关闭。我们的目标就是努力写出当需求变更时,可以尽量不修改原有的代码就可实现功能

作用:

  • 降低风险,因为上线的已有代码是经过用户多次使用和测试的结果,是较稳定的,盲目地去修改原有的代码可能会引入bug。
  • 提高代码复用性,比如我们通过继承去扩展父类方法,有时候我们还可以调用父类原有的方法,然后再增加自定义的部分,这样可以复用父类的方法
  • 后期维护,如果去修改原有的类,然后在里面根据不同的情况加入判断,这样会让后期维护变更更加困难。

举个栗子:

  • 比如在web项目里的service,假如我们一开始接入了jpa,然后用最原始的直接在里面new一个dao层的jpa对象接着进行操作类似 Dao dao = new JpaDaoImpl(),突然有一天说要换成mybatis,这时候就很难搞了,每个地方都要改,而如果一开始我们用的是工厂模式,通过工厂去具体决定用哪种中间件,那么我们修改的就很少了。
  • 再比如说你要用到某个类,但是你有自定义的需求需要在上面增加新的方法或者对于某个方法要自定义逻辑,不要直接去修改它,因为可能其他人还用到该类中的方法,而是直接继承它然后重写已有的方法或者增加新的方法,不去修改原来的代码扩展类来实现。

如何做:

  • 抽象:多通过接口或抽象类来约束一组行为,然后在使用该行为的地方多用接口和抽象类而不是直接引用实现类,另外接口的契约作用,应该是稳定且可靠的,不应经常发生变化。

2、里氏替换原则

3、依赖倒置原则:依赖倒置原则倡导我们要面向接口编程,不要面向实现编程

4、单一职责原则:每个类功能职责尽量单一存粹,这样可以降低其变更的可能性,如果职责太多那么发生变化的可能性也更高,就比如一个负责销售的类就不要在里面搞对产品的管理,销售的就负责销售就可以了。

作用:

  • 降低耦合:过多的职责那自然跟其他模块的耦合就变得高了。

5、接口隔离原则

6、迪米特法则

7、组合聚合复用原则

二、创建型设计模式

1、单例模式

/**
 * 单例模式,同个JVM进程中内存只有一个对象
 * spring中配置的单例Bean和mybatis中的ErrorContext严格意义上都不能算是真正的单例,因为单例Bean是讨论的同个spring容器的,而ErrorContext是ThreadLocal机制保证跟ErrorContext绑定它是讨论同个线程的
 * 1、如果每次都去用new创建一个新的对象对内存消耗很大
 * 2、有些场景需要有且仅有一个对象来实现业务,比如计数器等东西,还有全局数据共享比如应用启动时读配置,很多时候只需要读一次到处用
 */
/**
 * 饿汉模式,不会有并发问题
*/
class Singleton implements Serializable {
    //饿汉的缺点就是假如我只是想访问该类的静态属性,结果它直接就帮我创建了里面Singleton,造成不必要的资源消耗
    //可能我想等用到再创建,所以就出现了懒汉模式
    private static int num = 0;
    private static Singleton singleton = new Singleton();
    public static Singleton getInstance(){
        return singleton;
    }
}

/**
 * 懒汉模式,并发问题
 */
//class LazySingleton {
//    private static LazySingleton singleton = null;
//    public static LazySingleton getInstance(){
//        if(null == singleton){
//            singleton = new LazySingleton();
//        }
//        return singleton;
//    }
//}

/**
 * 懒汉模式,加锁解决并发但可能导致线程阻塞,性能上差
 */
class LazySingleton {
    private static volatile LazySingleton singleton = null;//volatile是为了解决多线程内存可见,让修改实时同步到各个线程
    public static LazySingleton getInstance(){
        if(null == singleton){
            //锁放判断里面,减少线程阻塞
            synchronized (LazySingleton.class){
                if(null == singleton){
                    singleton = new LazySingleton();
                }
            }
        }
        return singleton;
    }
}

/**
 * 静态内部类实现需求,虽然看着只是在饿汉模式上面包了一层内部类,但这样可以解决饿汉模式中引用静态变量却初始化了实例的问题
 */
class MySingleton {
    private static int num = 0;
    static class InnerSingleton{
        private static InnerSingleton singleton = new InnerSingleton();
    }
    public static InnerSingleton getInstance(){
        return InnerSingleton.singleton;
    }
}

/**
 * 枚举实现,跟饿汉一样即时加载,没得延迟,但它不会被反射和序列化破坏单例,其它的方式都会
 */
enum EnumSingleton implements Serializable{
    SINGLETON;
    public static EnumSingleton getInstance(){
        return SINGLETON;
    }
}

/**
 * 破解单例
 */
public class TestSingleton{
    public static void main(String[] args) throws Exception{
        //正常单例
        Singleton singleton_a = Singleton.getInstance();
        Singleton singleton_b = Singleton.getInstance();
        System.out.println("正常单例:" + (singleton_a == singleton_b));
        //反射破解
        Singleton singleton_c = Singleton.class.newInstance();
        Singleton singleton_d = Singleton.class.newInstance();
        System.out.println("反射破解:" + (singleton_c == singleton_d));
        //序列化破解
        ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
        objectOutputStream.writeObject(singleton_a);
        objectOutputStream.close();
        ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteOutputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteInputStream);
        Singleton singleton_e = (Singleton)objectInputStream.readObject();
        objectInputStream.close();
        System.out.println("序列化破解:" + (singleton_a == singleton_e));
        //枚举的序列化,还是单例,反射也一样效果
        EnumSingleton singleton_h = EnumSingleton.SINGLETON;
        ByteArrayOutputStream byteOutputStream1 = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream1 = new ObjectOutputStream(byteOutputStream1);
        objectOutputStream1.writeObject(singleton_h);
        objectOutputStream1.close();
        ByteArrayInputStream byteInputStream1 = new ByteArrayInputStream(byteOutputStream1.toByteArray());
        ObjectInputStream objectInputStream1 = new ObjectInputStream(byteInputStream1);
        EnumSingleton singleton_i = (EnumSingleton)objectInputStream1.readObject();
        objectInputStream1.close();
        System.out.println("枚举:" + (singleton_h == singleton_i));
    }
}

2、原型模式

/**
 * 原型模式:可以在不知道具体哪种子类的情况下进行精准克隆,而不用去if判断
 * 使用jdk的clone方法需实现 Cloneable接口
 * clone分浅拷贝和深拷贝,浅拷贝在复杂对象中只拷贝个地址,可以自己实现clone方法对于所有复杂对象进行拷贝,另外也可以用序列化方式实现
 */
public class TestPrototype {
    public static void main(String[] args) throws Exception{
        Prototype.copyDao(new FruitOrder());
    }
}
class Prototype{
    //假如需要复制多种类型的订单
    public static Order copyDao(Order order) throws Exception{
        Order o = null;
        //第一种:自己判断然后手动new再复制
//        if(order instanceof FruitOrder){
//            o = new FruitOrder();
//        }else if(order instanceof VegetableOrder){
//            o = new VegetableOrder();
//        }
        //原型模式
//        o = (Order)order.cloneObject();
        //原型模式,jdk帮我们实现的复制过程
        o = (Order)order.clone();
        return o;
    }
}

3、工厂方法模式和抽象工厂模式

/**
 * Calendar中的getInstance()方法和Spring的BeanFactory就是简单工厂模式,Spring的FactoryBean接口用的地方就是用工厂方法模式,
 * 还有mybatis的SqlSessionFactory也是工厂模式的体现
 * 一般Factory结尾的就是
 *
 * 例如:您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现
 * 工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如农场里既养动物又种植物,电器厂既生产电视机又生产洗衣机或空调
 */
public class TestFactory {
    public static void main(String[] args){
        //1、直接new的方式,很不灵活
//        Dao dao = new JpaDao();
        //利用工厂模式
        Dao dao = SimpleFactory.daoFactory();
        System.out.println(dao);
    }
}

/**
 * 简单/静态工厂模式(它不属于23种设计模式里),将创建类的职责从使用方提取到统一的工厂里面,实现初步解耦
 * 如果创建一个dao层对象直接使用new一个实现类的方式,例如 new JpaDao(),后期要改为mybatis就变得困难,每个地方就要改,耦合严重,修改困难。
 * 考虑把创建该对象的地方提取到一个共用的地方,我们称它为工厂
 * 但它所有类型的对象都在同个工厂里创建,如果不同类型需要传进类型值来判断,其实还是违反了开闭原则
 */
class SimpleFactory{
    public static Dao daoFactory(){
        //1、第一种方式直接new,这种虽然已经把创建该类从每个单独的使用方抽离出来,但始终还是在代码里手动创建,一旦修改需要改代码
//        return new JpaDao();
        //2、使用读取配置文件的方式,在配置文件指定类名,再利用反射创建实例
        try {
            Properties properties = new Properties();
            InputStream resourceAsStream = SimpleFactory.class.getResourceAsStream("/dao.properties");
            properties.load(resourceAsStream);
            String daoClass = (String)properties.get("daoClass");
            return (Dao)Class.forName(daoClass).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

/**
 * 工厂方法模式,在简单工厂模式的基础上进一步改进
 * 简单工厂模式在用于只有一种类型的对象创建上还能用,但假如需要同时存在多种比如上面的情况万一我们系统要用JPA又要用Mybatis,dao层接口它们都继承Dao接口,
 * 那我们用了同个工厂的话,就得在工厂里根据使用方传进来的类型去判断应创建的是什么实例,所以我们用工厂方法模式,对于每种类型都附带自己的一个工厂
 */
class FactoryMethod{
    public static Dao getDao(DaoFactory daoFactory){
        return daoFactory.getDao();
    }
}
interface DaoFactory{
    Dao getDao();
}
class JpaDaoFactory implements DaoFactory{
    public Dao getDao() {
        return new JpaDao();
    }
}
class MybatisDaoFactory implements DaoFactory{
    public Dao getDao() {
        return new MybatisDao();
    }
}

/**
 * 抽象工厂模式,在工厂方法模式的基础上进一步抽象
 * 工厂方法只有一种组件,抽象工厂可以实现多个组件生产
 */
class AbstractFactory{
}
interface AbstractFruitFactory{
    Apple getApple();
    Banana getBanana();
}
class AbstractJpaDaoFactory implements AbstractFruitFactory{
    public Apple getApple() {
        return new AppleA();
    }
    public Banana getBanana() {
        return new BananaA();
    }
}
class AbstractMybatisDaoFactory implements AbstractFruitFactory{
    public Apple getApple() {
        return new AppleB();
    }
    public Banana getBanana() {
        return new BananaB();
    }
}

4、建造者模式

/**
 * StringBuilder就是建造者模式,mybatis中对mybatis-config.xml这些的解析也是基于顶层的BaseBuilder类
 * 一般Builder结尾的就是
 *
 * 例如:JAVA 中的 StringBuilder
 * 公司采购员不可能自己去组装计算机,而是将计算机的配置要求告诉计算机销售公司,计算机销售公司安排技术人员去组装计算机,然后再交给要买计算机的采购员
 */
abstract class BaseBuilder{
    protected Product product = new Product();
    abstract BaseBuilder buildA();
    abstract BaseBuilder buildB();
    abstract BaseBuilder buildC();

    public Product getProduct(){
        return this.product;
    }
}

class MyBuilder extends BaseBuilder{
    @Override
    public BaseBuilder buildA(){
        product.setId(11);
        return this;
    }

    @Override
    public BaseBuilder buildB(){
        product.setName("");
        return this;
    }

    @Override
    public BaseBuilder buildC(){
        product.setUrl("");
        return this;
    }
}

//指挥者
class Director{
    BaseBuilder builder;
    public Director(BaseBuilder builder){
        this.builder = builder;
    }
    public Product build(){
        Product product = builder.buildA().buildB().buildC().getProduct();
        return product;
    }
}

三、结构型设计模式

1、代理模式

/**
 * 代理可以让客户端不需要知道真实类的操作内容,全权由代理类操办,当然也可以在代理中动态的为真实类增加功能比如日志记录
 * 静态代理:代理类实现和真实类一样的接口,并且持有一个真实类的引用,最后代理类进行代理或者功能扩展
 * jdk动态代理:Proxy.newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h),先是加载生成代理类的类加载器ClassLoader,然后是接口,最后是处理器InvocationHandler
 * cglib动态代理:Enhancer 增强器,设置类型、回调函数MethodInterceptor,最后create
 *
 * spring中的 AOP 就是应用代理最出名的
 * 代理分静态代理和动态代理,动态里又分jdk动态代理和cglib动态代理
 */

/*public class TestProxy {
    public static void main(String[] args){
        new CircleProxy(new RealCircle()).draw();//利用代理角色画圆
    }
}*/

interface BaseShape{
    void draw();
}

class RealCircle implements BaseShape{
    @Override
    public void draw() {
        System.out.println("画一个圆");
    }
}

class CircleProxy implements BaseShape{
    private BaseShape shape;
    public CircleProxy(BaseShape shape) {
        this.shape = shape;
    }
    @Override
    public void draw() {
        shape.draw();
        addColor();//可加可不加,代理可以实现功能扩展但不代表一定要有功能扩展
    }
    public void addColor(){
        System.out.println("加颜色");
    }
}

/** jdk动态代理 **/
class ProxyHandler implements InvocationHandler{
    BaseShape shape;
    public ProxyHandler(BaseShape shape) {
        this.shape = shape;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(shape,args);
    }
}

/*public class TestProxy {
    public static void main(String[] args){
        BaseShape shape = new RealCircle();
        BaseShape s = (BaseShape)Proxy.newProxyInstance(shape.getClass().getClassLoader(), shape.getClass().getInterfaces(), new ProxyHandler(shape));
        System.out.println(shape + "," + s);//hashcode一样
        System.out.println(shape.equals(s));//但是并不是同一个对象
    }
}*/

/** cglib动态代理 **/
class CglibProxy implements MethodInterceptor {
    BaseShape shape;
    public CglibProxy(BaseShape shape) {
        this.shape = shape;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        return methodProxy.invoke(shape,args);
    }
}

public class TestProxy {
    public static void main(String[] args){
        BaseShape shape = new RealCircle();

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(shape.getClass());
        enhancer.setCallback(new CglibProxy(shape));
        BaseShape s = (BaseShape)enhancer.create();

        System.out.println(shape + "," + s);//hashcode一样
        System.out.println(shape.equals(s));//但是并不是同一个对象
    }
}

2、适配者模式

/**
 * 适配器模式:将类接口转换成另一种接口为了兼容使用方
 * 适配器使用方是强行去兼容新接口,所以适配和被适配是差别比较大的,但这样可以在不修改原有适配不了的情况下达到适配的作用
 *
 * 类适配:适配器继承被适配者并且实现目标接口
 * 对象适配:适配器实现目标接口并且持有一个被适配者的引用(有和组合模式相似)
 * 双向适配:适配器实现两个目标接口,同时持有两个的引用,交叉适配
 *
 * 应用场景:InputStreamReader(InputStream) 和java.io.OutputStreamWriter(OutputStream),通过InputStreamReader、OutputStreamWriter适配器将字节流转换为字符流
 * SpringMVC中,HandlerAdaptor
 */
public class TestAdapter {
//    public static void main(String[] args){
//        staticAdapter.action();
//    }
}
//目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口
interface Target{
    void doing();
}
//被适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口
class Adaptee{
    public void eat() {
        System.out.println("开始吃饭");
    }
}

/** 类适配 **/
class AdapterCat extends Adaptee implements Target {
    @Override
    public void doing() {
        eat();
    }
}
/** 类适配 **/

/** 对象适配 **/
class AdapterDog implements Target {
    private Adaptee adaptee;
    public AdapterDog(Adaptee adaptee){
        this.adaptee = adaptee;
    }
    @Override
    public void doing() {
        adaptee.eat();
    }
}
/** 对象适配 **/

/** 双向适配 **/
// 目标接口
interface TwoTarget{
    void doing();
}
//适配者接口
interface TwoAdaptee{
    void eat();
}
//目标实现
class TargetRealize implements TwoTarget{
    @Override
    public void doing() {
        System.out.println("目标执行");
    }
}
//适配者
class AdapteeRealize implements TwoAdaptee{
    @Override
    public void eat() {
        System.out.println("适配者执行");
    }
}
//双向适配器
class TwoAdapter implements TwoAdaptee,TwoTarget{
    private TwoAdaptee twoAdaptee;
    private TwoTarget twoTarget;
    public TwoAdapter(TwoAdaptee twoAdaptee){
        this.twoAdaptee = twoAdaptee;
    }
    public TwoAdapter(TwoTarget twoTarget){
        this.twoTarget = twoTarget;
    }
    @Override
    public void doing() {
        twoAdaptee.eat();
    }

    @Override
    public void eat() {
        twoTarget.doing();
    }
}
class Adapter {
    public static void action(){
        TwoAdapter twoAdaptee = new TwoAdapter(new AdapteeRealize());
        twoAdaptee.doing();
        TwoAdapter twoTarget = new TwoAdapter(new TargetRealize());
        twoTarget.eat();
    }
}
/** 双向适配 **/

3、装饰器模式

/**
 * 装饰类和被装饰类可以独立,不会耦合
 * 继承的一个替代模式,能够动态的扩展一个类的功能
 * 抽象装饰类实现和被装饰类一样的接口 Compenent,并且持有一个被装饰类的引用,最后具体装饰类继承抽象装饰类进行扩展
 *
 * 实际上装饰器模式和代理模式极其相似,都是需要实现相同的接口且都可以不侵入原类的情况下动态的增加额外的功能
 * 但代理模式强调的是代理,也就是说目的在于隐藏原类而使用代理类,而代理类可能增加了功能也可以不增加功能
 * 而装饰器模式更多强调装饰,也就是说它一定是在原类的基础上增加了功能的
 */
public class TestDecorator {
    public static void main(String[] args){
        new CircleDecorator(new Circle()).draw();
    }
}

/**
 * 给一个圆上色,也就是增加装饰
 */
interface Shape{
    void draw();
}

class Circle implements Shape{
    @Override
    public void draw() {
        System.out.println("画一个圆");
    }
}

abstract class AbstractCircleDecorator implements Shape{
    private Shape shape;
    public AbstractCircleDecorator(Shape shape) {
        this.shape = shape;
    }
    @Override
    public void draw() {
        shape.draw();
    }
}

class CircleDecorator extends AbstractCircleDecorator{
    public CircleDecorator(Shape shape) {
        super(shape);
    }

    @Override
    public void draw() {
        super.draw();
        addColor();
    }
    public void addColor(){
        System.out.println("加颜色");
    }
}

4、桥接模式

/**
 * 桥接模式:用于不同属性或者维度之间的组合,比如电脑有品牌维度(联想和戴尔)和机型维度(台式机和笔记本)
 *
 * 被桥接类实现接口,桥接抽象类持有一个被桥接接口的引用,最后具体桥接类继承抽象类进行桥接
 *
 */
public class TestBridge {
    public static void main(String[] args){
    }
}
/**
 * 图形和颜色两个维度
 */
interface DrawShape{
    void draw(String color);
}

class DrawCircle implements DrawShape{
    @Override
    public void draw(String color) {
        System.out.println("画一个圆" + color);
    }
}
class DrawSquare implements DrawShape{
    @Override
    public void draw(String color) {
        System.out.println("画一个方" + color);
    }
}

abstract class DrawColor{
    protected DrawShape shape;
    public DrawColor(DrawShape shape) {
        this.shape = shape;
    }
    abstract void draw();
}

class CircleColor extends DrawColor{
    public CircleColor(DrawShape shape) {
        super(shape);
    }
    @Override
    public void draw() {
        shape.draw("黑色");
    }
}

class SquareColor extends DrawColor{
    public SquareColor(DrawShape shape) {
        super(shape);
    }
    @Override
    public void draw() {
        shape.draw("白色");
    }
}

5、外观模式

/**
 * 外观模式类似建造者模式一样,不过那个是创建型的,外观是结构型的
 * 它就是把多个需要一起办的事情做一个整合暴露给客户端,客户端只需要对接一个接口而不需要独自面对多个接口
 *
 * 例如:去医院看病,可能要去挂号、门诊、划价、取药,让患者或患者家属觉得很复杂,如果有提供接待人员,只让接待人员来处理
 */
public class TestFacade {
    public static void main(String[] args){
    }
}

//外观(Facade)角色:为多个子系统对外提供一个共同的接口
class Facade{
    private FacadeCat facadeCat = new FacadeCat();
    private FacadeDoor facadeDoor = new FacadeDoor();
    public void doing(){
        facadeCat.eat();
        facadeDoor.close();
    }
}

//子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它
class FacadeCat{
    public void eat() {
        System.out.println("猫开始吃饭");
    }
}
//子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它
class FacadeDoor{
    public void close() {
        System.out.println("关门");
    }
}

四、行为型设计模式

1、模板模式

/**
 * 固定部分行为封装在一起,变化部分交由子类来实现,提取了公共代码便于维护
 *
 * 抽象父类定义模板方法,模板方法是固定不变的部分,里面调用会变化的那部分方法,而变化的又交由子类的实现
 *
 * 例如:开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存
 *
 */
public class TestTemplateMethod {
    public static void main(String[] args){
        BaseTemplate game = new Game();
        game.play();
    }
}

abstract class BaseTemplate{
    public void play(){
        start();
        doing();
        end();
    }
    abstract void start();
    abstract void doing();
    abstract void end();
}

class Game extends BaseTemplate{
    @Override
    void start() {
        System.out.println("游戏开始");
    }

    @Override
    void doing() {
        System.out.println("游戏进行");
    }

    @Override
    void end() {
        System.out.println("游戏结束");
    }
}

2、策略模式

/**
 * 策略模式:解决多重条件语句带来的维护困难,将相同行为的不同实现转移到父类和子类的继承上
 *
 * 定义策略接口,不同策略对策略接口做自定义实现,接着通过 Context类构造器注入不同策略,来完成对策略的使用
 *
 * 例如:出行旅游可以乘坐飞机、乘坐火车、骑自行车或自己开私家车等,超市促销可以釆用打折、送商品、送积分等方法
 */
public class TestStrategy {
    public static void main(String[] args){
        new Context(new AddCaculate()).getResult(10,5);
    }
}

class Context{
    Strategy strategy;
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public int getResult(int be, int af){
        return strategy.caculate(be,af);
    }
}

interface Strategy{
    int caculate(int be,int af);
}

class AddCaculate implements Strategy{
    @Override
    public int caculate(int be, int af) {
        return be + af;
    }
}

class SubCaculate implements Strategy{
    @Override
    public int caculate(int be, int af) {
        return be - af;
    }
}

3、观察者模式

/**
 * 观察者模式:一群观察者观察着被观察者,就像发布/订阅里的订阅者观察着主题看是否发布消息一样
 *
 * 定义主题类,里面有观察者的列表,更新时循环通知各位观察者
 * 抽象观察者类定义统一通知方法,具体观察者构造方法将自己添加到观察者列表里,且实现通知方法
 *
 * 例如:拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价
 *
 */
public class TestObserver {
    public static void main(String[] args){
        Subject subject = new Subject();
        new BoyObserver(subject);
        new GirlObserver(subject);
        subject.notifyObserver();
    }
}

class Subject{
    private List observers = Lists.newArrayList();
    public void add(Observer observer){
        observers.add(observer);
    }

    public void notifyObserver(){
        for(Observer observer:observers){
            observer.update();
        }
    }
}

abstract class Observer{
    public abstract void update();
}

class BoyObserver extends Observer{
    public BoyObserver(Subject subject) {
        subject.add(this);
    }
    @Override
    public void update() {
        System.out.println("更新");
    }
}
class GirlObserver extends Observer{
    public GirlObserver(Subject subject) {
        subject.add(this);
    }
    @Override
    public void update() {
        System.out.println("更新");
    }
}

4、责任链模式

/**
 * 责任链模式:对象不需要知道链,可以改变链内成员或者次序动态的增加和删除责任
 *
 * 抽象类定义抽象处理方法和在构造器注入下一个处理的链,各个链继承抽象类在处理方法完成自身工作后判断是否有下一条链,有则进行处理
 *
 * 应用场景:Filter链,js冒泡
 */
public class TestChain {
    public static void main(String[] args){
        AbstractChain second = new SecondChain(null);
        AbstractChain first = new FirstChain(second);
        first.doing();

    }
}

abstract class AbstractChain{
    AbstractChain next;
    public AbstractChain(AbstractChain next) {
        this.next = next;
    }
    public abstract void doing();
}

class FirstChain extends AbstractChain{
    public FirstChain(AbstractChain next) {
        super(next);
    }
    @Override
    public void doing() {
        System.out.println("第一个");
        if(null != next){
            next.doing();
        }
    }
}

class SecondChain extends AbstractChain{
    public SecondChain(AbstractChain next) {
        super(next);
    }
    @Override
    public void doing() {
        System.out.println("第二个");
        if(null != next){
            next.doing();
        }
    }
}

5、中介者模式

/**
 * 中介者模式:减少对象的关联,通过中介者来解耦形成网状结构
 *
 * 定义抽象中介者提供注册和中介发送方法,具体中介者用列表存储同伴类,注册方法用来注册同伴类,发送方法给同伴之间做中介
 * 定义抽象同伴类构造方法注入中介者,同时定义接收和发送方法,具体同伴类自定义实现
 * 使用者创建中介者,然后把所有同伴类添加到中介者,然后就可以进行沟通了
 *
 * 应用场景:MVC中的 C 就是 M 和 V 之间的中介者
 * java.util.Timer就是一个中介者,TimerTask就是同事类,通过sched进行协调
 * 媒体网关
 * 注册中心
 */
class TestMediator {
    public static void main(String[] args){
        BaseMediator mediator = new Mediator();
        BaseColleague firstColleague = new FirstColleague(mediator);
        BaseColleague secondColleague = new SecondColleague(mediator);
        mediator.register(firstColleague);
        mediator.register(secondColleague);
        firstColleague.send();
        secondColleague.send();
    }
}

abstract class BaseMediator{
    abstract void register(BaseColleague colleague);
    abstract void send(BaseColleague colleague,String message);
}

class Mediator extends BaseMediator{
    List colleagues = Lists.newArrayList();
    @Override
    void register(BaseColleague colleague) {
        colleagues.add(colleague);
    }
    @Override
    void send(BaseColleague colleague,String message) {
        for(BaseColleague c:colleagues){
            if(!c.equals(colleague)){
                c.receive(message);
            }
        }
    }
}

abstract class BaseColleague{
    BaseMediator mediator;
    public BaseColleague(BaseMediator mediator) {
        this.mediator = mediator;
    }
    abstract void receive(String message);
    abstract void send();
}

class FirstColleague extends BaseColleague{
    public FirstColleague(BaseMediator mediator) {
        super(mediator);
    }
    @Override
    void receive(String message) {
        System.out.println("一号接收到:" + message);
    }
    @Override
    void send() {
        mediator.send(this,"我是一号");
    }
}
class SecondColleague extends BaseColleague{
    public SecondColleague(BaseMediator mediator) {
        super(mediator);
    }
    @Override
    void receive(String message) {
        System.out.println("二号接收到:" + message);
    }
    @Override
    void send() {
        mediator.send(this,"我是二号");
    }
}

 

你可能感兴趣的:(java)