几种常用的设计模式初步理解

代理模式&装饰模式


想到哪里写到哪里。

区别:
代理模式,注重对对象某一功能的流程把控和辅助。它可以控制对象做某些事,重心是为了借用对象的功能完成某一流程,而非对象功能如何。
装饰模式,注重对对象功能的扩展,它不关心外界如何调用,只注重对对象功能的加强,装饰后还是对象本身。

Spring的AOP的原理就是借助动态代理。

举个例子,例子全部来源参考链接1

//定义接口
public interface IChild {
   
    void eat();
}
//创建孩子类,实现吃饭的功能
public class Child implements IChild{
    
    @Override
    public void eat() {
        
        Log.e("TAG","孩子吃饭");
    }
}
//代理模式,在孩子吃饭之前,需要父母做代理,完成做饭和收拾的功能
//但是注意,代理并没有改变孩子吃饭的行为
//即孩子主动做出的行为没有被修改,增加的是另一个人的行为
//这是与装饰模式不同的地方
public class Parent implements IChild{

    private Child child;

    private Parent(Child child){

        this.child = child;
    }

    @Override
    public void eat() {

        Log.e("TAG","父母做饭");
        child.eat();
        Log.e("TAG","父母收拾餐具");
    }
}
//装饰模式
//这时候没有父母做代理,而是由孩子自己做饭和收拾。即扩展对象本身的方法
public class ChildWrapper implements IChild{
    
    private Child child;
    
    public ChildWrapper(Child child){
        this.child = child;
    }
    
    @Override
    public void eat() {
        
        Log.e("TAG","孩子做饭");
        
        child.eat();
        
        Log.e("TAG","孩子收拾餐具");
    }
}

单例模式Singleton Pattern


ps.突然发现,singlenton这个单词在我看的有关IOC Bean的作用域也用到了(随口一提,Spring到现在还一知半解orz

一个类只有一个实例,即一个类只有一个对象实例。

特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。

优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。

缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

//创建一个单例
public class SingleObject {
 
   //创建 SingleObject 的一个对象
   private static SingleObject instance = new SingleObject();
 
   //让构造函数为 private,这样该类就不会被实例化
   private SingleObject(){}
 
   //获取唯一可用的对象
   public static SingleObject getInstance(){
      return instance;
   }
 
   public void showMessage(){
      System.out.println("Hello World!");
   }
}

//获取唯一的对象
public class SingletonPatternDemo {
   public static void main(String[] args) {
 
      //不合法的构造函数
      //编译时错误:构造函数 SingleObject() 是不可见的
      //SingleObject object = new SingleObject();
 
      //获取唯一可用的对象
      SingleObject object = SingleObject.getInstance();
 
      //显示消息
      object.showMessage();
   }
}

单例模式的几种实现方法:

  1. 懒汉式:在类加载时不初始化。
  2. 饿汉式:在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快。
//懒汉,线程不安全
public class SingletonDemo1 {
    private static SingletonDemo1 instance;//唯一实例
    private SingletonDemo1(){}
    public static SingletonDemo1 getInstance(){
        if (instance == null) {
            instance = new SingletonDemo1();//这个时候才初始化
        }
        return instance;
    }
}

//懒汉,线程安全
//通过添加synchronized关键字
//优点:第一次调用才初始化,避免内存浪费。
//缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    	if (instance == null) {  
        	instance = new Singleton();  
    	}  
    	return instance;  
    }  
}

//饿汉,线程安全
//优点:没有加锁,执行效率会提高。
//缺点:类加载时就初始化,浪费内存。
public class Singleton {  
    private static Singleton instance = new Singleton();  //类加载时就初始化
    private Singleton (){}  
    public static Singleton getInstance() {  
    	return instance;  
    }  
}

//双检锁/双重校验锁(DCL,即 double-checked locking)
//实现难度:较复杂.采用双锁机制,安全且在多线程情况下能保持高性能。
public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    	if (singleton == null) {  
        	synchronized (Singleton.class) {  
        	if (singleton == null) {  
            	singleton = new Singleton();  
        	}  
        }  
    }  
    return singleton;  
    }  
}

工厂模式


工厂模式一共有三种:简单工厂模式、工厂方法模式和抽象工厂模式

简单工厂模式

emm我试着纯手打代码,可能会编译不过。理解其中的意思即可,顺便让自己加深下印象。

public abstract class IFruit {
    /**
     * 描述水果有关的抽象方法
     * 产品的抽象类。
     */
    public abstract void eat();
}

//产品的具体类
public class IApple extends IFruit {
    @Override
    public void eat() {
        System.out.println("苹果真好吃");
    }
}

//产品的具体类
public class IOrange extends IFruit {
    @Override
    public void eat() {
        System.out.println("橘子真好吃");
    }
}

//产品的具体类
public class IPear extends IFruit {
    @Override
    public void eat() {
        System.out.println("梨真好吃");
    }
}

//简单工厂类
public class SimpleFruitFactory {

    public static IFruits createFruit(String type) {
        switch (type) {
            case "Apple":
                return new IApple();
            case "Orange":
                return new IOrange();
            case "Pear":
                return new IPear();
        }
    }
}

//测试
public class FactoryTest {  
  
    public static void main(String[] args) {  
        SimpleFruitFactory factory = new SendFactory();  
        IFruit fruit = factory.creatFruit("Apple");  
        fruit.eat();  
    }  
}  

特点

  1. 它是一个具体的类,非接口抽象类。有一个重要的create()方法,利用 if 或者 switch 创建产品并返回。
  2. create()方法通常是静态的,所以也称之为静态工厂。

缺点

  1. 扩展性差(我想增加一种水果,除了新增一个水果产品类,还需要修改工厂类方法)
  2. 不同的产品需要不同额外参数的时候 不支持。

工厂方法模式

工厂方法模式提供一个用于创建对象的接口(工厂接口),让其实现类(工厂实现类)决定实例化哪一个类(产品类),并且由该实现类创建对应类的实例。

代码全部来源于参考链接5。如有侵权,请联系我删除。

//工厂接口
public interface IceCreamFactory {

    public IceCream createIceCream();
}
//分别定义AppleIceCreamFactory、BananaIceCreamFactory、OrangeIceCreamFactory
//继承刚刚定义的工厂接口,制作三种口味冰淇淋
public class AppleIceCreamFactory implements IceCreamFactory {

    public IceCream createIceCream() {
        return new AppleIceCream();
    }
}

public class BananaIceCreamFactory implements IceCreamFactory {

    public IceCream createIceCream() {
        return new BananaIceCream();
    }
}

public class OrangeIceCreamFactory implements IceCreamFactory{

    public IceCream createIceCream() {
        return new OrangeIceCream();
    }
}

// 客户端代码
public class Client {

    /**
     * @param args
     */
    public static void main(String[] args) {

        //生产苹果味冰激凌
        IceCreamFactory appleFactory = new AppleIceCreamFactory();
        IceCream appleIceCream = appleFactory.createIceCream();
        appleIceCream.taste();

        //生产香蕉口味冰激凌
        IceCreamFactory  bananaFactory = new BananaIceCreamFactory();
        IceCream bananaIceCream = bananaFactory.createIceCream();
        bananaIceCream.taste();

        //生产橘子口味冰激凌
        IceCream orangeIceCream = new OrangeIceCreamFactory().createIceCream();
        orangeIceCream.taste();
    }
}

可以看到,每个工厂只生产一种产品,客户端通过不同的工厂去生产不同的产品,而生产哪一产品的逻辑交给客户端这边去处理了。

简单工厂模式的问题在于,如果想要新增一个口味的水果,不仅要新增一个具体产品类,还需要修改简单工厂类,还要在switch里边,新增一个case分支,违背了开闭原则,扩展性差。而对于工厂方法模式来说,不需要在具体工厂里面修改,而是新增一个具体工厂,让他继承抽象工厂就可以。

抽象工厂模式

抽象工厂模式(Abstract Factory),提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。

继续上面冰淇淋的例子。消费者已经不满足于只能选择冰淇淋的口味,可能会想要选择吃大份的冰淇淋或是小份的。

因此,先定义两个冰淇淋的接口。

public interface BigIceCream {

    public void taste();

}

public interface SmallIceCream {

    public void taste();

}

定义各个口味的冰激凌,继承刚刚定义的接口,实现其方法

public class BigAppleIceCream implements BigIceCream {

    public void taste() {
        System.out.println("这是苹果味冰激凌(大份)");
    }
}

public class SmallAppleIceCream implements SmallIceCream {

    public void taste() {
        System.out.println("这是苹果味冰激凌(小份)");
    }
}

//后边还有四个类
//BigBananaIceCream、SmallBananaIceCream、BigOrangeIceCream、SmallOrangeIceCream

定义工厂接口,这里有两个方法,分别生产小份大的和大份的

public interface IceCreamFactory {

    public BigIceCream createBigIceCream();

    public SmallIceCream createSmallIceCream();
}

定义三个工厂类继承上边的接口并实现其方法

public class AppleIceCreamFactory implements IceCreamFactory {

    public BigIceCream createBigIceCream() {
        return new BigAppleIceCream();
    }

    public SmallIceCream createSmallIceCream() {
        return new SmallAppleIceCream();
    }
}

public class BananaIceCreamFactory implements IceCreamFactory {

    public BigIceCream createBigIceCream() {
        return new BigBananaIceCream();
    }

    public SmallIceCream createSmallIceCream() {
        return new SmallBananaIceCream();
    }
}

public class OrangeIceCreamFactory implements IceCreamFactory {

    public BigIceCream createBigIceCream() {
        return new BigOrangeIceCream();
    }

    public SmallIceCream createSmallIceCream() {
        return new SmallOrangeIceCream();
    }
}

客户端代码

public class Client {

    public static void main(String[] args) {

        //生产苹果味冰激凌
        IceCreamFactory appleIceCreamFactory = new AppleIceCreamFactory();
        BigIceCream appleBigIceCream = appleIceCreamFactory.createBigIceCream();
        SmallIceCream appleSmallIceCream = appleIceCreamFactory.createSmallIceCream();
        appleBigIceCream.taste();
        appleSmallIceCream.taste();

        //生产香蕉味冰激凌
        IceCreamFactory bananaIceCreamFactory = new BananaIceCreamFactory();
        BigIceCream bananaBigIceCream = bananaIceCreamFactory.createBigIceCream();
        SmallIceCream bananaSmallIceCream = bananaIceCreamFactory.createSmallIceCream();
        bananaBigIceCream.taste();
        bananaSmallIceCream.taste();

        //生产橘子味冰激凌
        IceCreamFactory orangeIceCreamFactory = new OrangeIceCreamFactory();
        BigIceCream orangeBigIceCream = orangeIceCreamFactory.createBigIceCream();
        SmallIceCream orangeSmallIceCream = orangeIceCreamFactory.createSmallIceCream();
        orangeBigIceCream.taste();
        orangeSmallIceCream.taste();
    }
}

之所以叫抽象工厂,是因为和工厂方法相比,这里有多个抽象产品类存在(即大份的冰激凌和小份的冰激凌),每个抽象产品类可以派生出多个具体的产品,生产的是系列产品,其工厂接口相对于工厂方法模式而言,是有多个方法的,用来生产不同的抽象产品。

总结:都来自这里
简单工厂模式,工厂类是整个模式的关键所在,包含了必要的逻辑判断,能够外界给定的信息, 决定究竟创建哪个具体类的对象。工厂方法模式是对简单工厂方法模式的一个抽象,抽离出了一个Factory类(或者接口),这个接口不负责具体产品的生产,而只是指定一些规范,具体的生产工作由其子类去完成。这个模式中,工厂类和产品类往往是一一对应的,完全解决了简单工厂模式中违背“开闭原则”的问题,实现了可扩展;抽象工厂模式的特点是存在多个抽象产品类,每个抽象产品类可以派生出多个具体产品类,工厂提供多种方法,去生产“系列”产品。

简单工厂模式适用于工厂类需要创建的对象比较少的情况,客户只需要传入具体的参数,就可以忽略工厂的生产细节,去获取想要的对象;工厂方法模式,主要是针对单一产品结构的情景;抽象工厂模式则是针对多级产品结构(系列产品)的一种工厂模式。最后在说一下,每种模式都有自己的优点和弊端,没有最好的模式,只有最适合的模式,只要符合实际开发需求就是最好的。

观察者模式

在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。类似于订阅消息。

该模式包含四种角色:

  1. 抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
  2. 抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
  3. 具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
  4. 具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。

代码全部来源于参考链接6

有一个微信公众号服务,不定时发布一些消息,关注公众号就可以收到推送消息,取消关注就收不到推送消息。

1、首先定义一个抽象被观察者接口

package com.jstao.observer;

/***
 * 抽象被观察者接口
 * 声明了添加、删除、通知观察者方法
 * @author jstao
 *
 */
public interface Observerable {
    
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObserver();
    
}

2、定义一个抽象观察者接口

package com.jstao.observer;

/***
 * 抽象观察者
 * 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。
 * @author jstao
 *
 */
public interface Observer {
    public void update(String message);
}

3、定义被观察者,实现了Observerable接口,对Observerable接口的三个方法进行了具体实现,同时有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合即可。

package com.jstao.observer;

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

/**
 * 被观察者,也就是微信公众号服务
 * 实现了Observerable接口,对Observerable接口的三个方法进行了具体实现
 * @author jstao
 *
 */
public class WechatServer implements Observerable {
    
    //注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程
    private List<Observer> list;
    private String message;
    
    public WechatServer() {
        list = new ArrayList<Observer>();
    }
    
    @Override
    public void registerObserver(Observer o) {
        
        list.add(o);
    }
    
    @Override
    public void removeObserver(Observer o) {
        if(!list.isEmpty())
            list.remove(o);
    }

    //遍历
    @Override
    public void notifyObserver() {
        for(int i = 0; i < list.size(); i++) {
            Observer oserver = list.get(i);
            oserver.update(message);
        }
    }
    
    public void setInfomation(String s) {
        this.message = s;
        System.out.println("微信服务更新消息: " + s);
        //消息更新,通知所有观察者
        notifyObserver();
    }

}

4、定义具体观察者,微信公众号的具体观察者为用户User

package com.jstao.observer;

/**
 * 观察者
 * 实现了update方法
 * @author jstao
 *
 */
public class User implements Observer {

    private String name;
    private String message;
    
    public User(String name) {
        this.name = name;
    }
    
    @Override
    public void update(String message) {
        this.message = message;
        read();
    }
    
    public void read() {
        System.out.println(name + " 收到推送消息: " + message);
    }
    
}

5、编写一个测试类

首先注册了三个用户,ZhangSan、LiSi、WangWu。公众号发布了一条消息"PHP是世界上最好用的语言!",三个用户都收到了消息。

用户ZhangSan看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其他用户

还是正常能收到推送消息。

package com.jstao.observer;

public class Test {
    
    public static void main(String[] args) {
        WechatServer server = new WechatServer();
        
        Observer userZhang = new User("ZhangSan");
        Observer userLi = new User("LiSi");
        Observer userWang = new User("WangWu");
        
        server.registerObserver(userZhang);
        server.registerObserver(userLi);
        server.registerObserver(userWang);
        server.setInfomation("PHP是世界上最好用的语言!");
        
        System.out.println("----------------------------------------------");
        server.removeObserver(userZhang);
        server.setInfomation("JAVA是世界上最好用的语言!");
        
    }
}

测试结果如下图:
在这里插入图片描述

参考链接:

  1. https://www.jianshu.com/p/c06a686dae39 代理模式和装饰器模式的区别
  2. http://www.runoob.com/design-pattern/singleton-pattern.html 单例模式
  3. https://www.cnblogs.com/Ycheng/p/7169381.html 常见的几种单例模式
  4. https://www.cnblogs.com/zailushang1996/p/8601808.html java 三种工厂模式
  5. https://blog.csdn.net/weixin_35985385/article/details/81430545 三大工厂模式的代码实现及总结
  6. https://www.cnblogs.com/luohanguo/p/7825656.html JAVA设计模式之观察者模式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值