常用设计模式复习

单例

定义

​ 保证一个类仅有一个实例,并提供一个访问它的全局访问点。

image

写法

单例模式有多种写法,各有利弊:

  1. 饿汉模式(预加载)
private class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton (){
    }
    public static Singleton get Instance() {
        return instance;
    }
}

这种方式在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快。 这种方式基于类加载机制避免了多线程的同步问题,但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到懒加载的效果。

  1. 懒汉模式(懒加载)
public class Sington {
    private static Singleton instance;
    private Singleton (){
    }
    public static Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

懒汉模式申明了一个静态对象,在用户第一次调用时初始化,虽然节约了资源,但第一次加载时需要实例化,反映稍慢一些,而且在多线程不能正常工作。

装饰器

介绍:装饰模式是结构型设计模式之一,不必改变类文件和使用继承的情况下,动态地扩展一个对象的功能,是继承的替代方案之一。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

定义

动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。

原型模式
  • Component:抽象组件,给对象动态的添加职责
  • ConcreteComponent:组件具体实现类。
  • Decorator:抽象装饰者,继承Component,从外类来拓展Component类的功能,但对于Component来说无需知道Decorator的存在。
  • ConcreteDecorator:装饰者具体实现类。

案例

​ 购买奶茶时,可以要求在其中加入各种调料,比如珍珠、烧仙草、什果、巧克力等。奶茶店会根据底茶和加入的调料收取不同的费用。奶茶的基类如下:

public abstract class Tea {
    String description="";
    public String getDescription(){
        return description;
    }
    public abstract double cost();
}

现有两种基础茶(RedTea、GreenTea),价格分别为 10 元和 9 元,4 种调料(Pearl、GrassJelly、 Fruit、Chocolate),价格分别为 5 元、6 元、7 元、8 元。使用装饰器模式,编写 Tea 的子类和各种调料对应的装饰器以及所需的接口和基类,能够输出特定奶茶产品的 description 和 cost.

public abstract class Dressing extends Tea{
    //配料抽象类
    private Tea tea;
    public Dressing(Tea tea){
        this.tea = tea;
    }
}
public class Pearl extends Dressing{
    //珍珠类
    String desctiption = "珍珠";

    public Pearl(Tea tea){
        super(tea);
    }
    @Override 
    public String getDescription(){
        return tea.getDescription() + this.descrition;
    }
    @Override
    public double cost(){
        rturn tea.cost()+5;
    }
}
public class RedTea extends Tea{
    String desctription = "红茶";
    @Override
    public double cost(){
        return 10;
    } 
}

原型

原型模式定义

​ 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。

原型模式
  • Client:客户端角色。
  • Prototype:抽象原型角色,抽象类或者接口,用来声明clone方法。
  • ConcretePrototype:具体的原型类,是客户端角色使用的对象,即被复制的对象。

❗ 需要注意的是,Prototype通常是不用自己定义的,因为拷贝这个操作十分常用,Java中就提供了Cloneable接口来支持拷贝操作,它就是原型模式中的Prototype。当然,接口也有其他的实现方式。

简单实现

原型模式的核心是clone方法,通过该方法进行拷贝,这里举一个名片拷贝的例子。

public class BusinessCard implements Cloneable {
    private String name;
    private String company;
    public BusinessCard(){
        System.out.println("执行构造函数BusinessCard");
    }
    public void setName(String name){
        this.name = name;
    }
    public void setCompany(String commpany){
        this.company = company;
    }
    @Override
    public BusinessCard clone(){
        BusinessCard businessCard = null;
        try{
            businessCard = (BusinessCard) super.clone();
        } catch(CloneNotSupportException e) {
            e.printStackTrace();
        }
        return businessCard;
    }
    public void show() {
        System.out.println("name:"+name);
        System.out.println("company:"+company);
    }
}

BusinessCard类实现了Cloneable接口,它是一个标识接口,表示这个对象是可拷贝的,只要重写clone方法就可以实现拷贝。如果实现了Cloneable接口却没有重写clone方法就会报错。❗ 需要注意的是,clone方法不是在Cloneable接口中定义的(Cloneable接口中没有定义任何方法),而是在Object中定义的。

//客户端调用
public class client {
    public static void main(String[] args) {
        BusinessCard businessCard = new BusinessCard();
        businessCard.setName("张三");
        businessCard.setCompant("Huawei");
        //拷贝名片
        BusinessCard cloneCard1 = businessCard.clone();
        cloneCard1.setName("李四");
        cloneCard1.setCompany("Ali");
        
        businessCard.show();
        cloneCard1.show();
    }
}

观察者

定义

​ 观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

观察者模式
  • Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
  • ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
  • Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
  • ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。

简单实现

观察者模式这种发布-订阅的形式可以用公众号来举例

抽象观察者 (Observer)
public interface Observer {
    public void update(String message);
    //定义了一个更新的方法
}
具体观察者(ConcreteObserver)
public class User implements Observer {
    //用户名
    private String name;
    public User(String name) {
        this.name = name;
    }
    @Override
    public void update(String message) {
        System.out.println(name+"-"+message);
    }
}
抽象被观察者(Subject)
public interface Subject{
    /**
     * 增加订阅者
     * @param observer
     */
    public void attach(Observer observer);
     /**
     * 删除订阅者
     * @param observer
     */
    public void detach(Observer observer);
    /**
     * 通知订阅者更新消息
     */
    public void notify(String message);
}
具体被观察者(ConcreteSubject)

被观察者的实例,里面存储了订阅该公众号的用户,并实现了抽象主题中的方法:

public class SubscriptionSubject implements Subject {
    //储存订阅公众号的微信用户
    private List<Observer> userList = new ArrayList<Observer>();
    @Override
    public void attach(Observer observer) {
        userList.add(observer);
    }
    
    @Override
    puiblic void detach(Observer observer) {
        userList.remove(observer);
    }
    
    @Override
    public void notify(String message) {
        for(Observer observer : userList){
            observer.update(message);
        }
    }
}
客户端调用
public class Client{
    public static  void main(String[] args) {
        SubscriptionSubject mSubscriptionSubject=new SubscriptionSubject();
        //创建用户
        User user1 = new User("Tony");
        ...
        //订阅公众号
        msubscriptionSubject.attach(user1);
        
        //公众号内容更新
        mSubscriptionSubject.notify("您关注的公众号更新了");
    }
}

动态代理

代理模式介绍

代理即为其他对象提供一种代理以控制这个对象的访问。代理模式也叫委托模式,是结构型设计模式的一种。在现实生活中我们用到类似代理模式的场景有很多,比如代购、代理上网、打官司等。

代理模式
  • Subject:抽象主题类,声明真实主题与代理的共同接口方法。
  • RealSubject:真实主题类,定义了代理所表示的真实对象,客户端通过代理类间接的调用真实主题类的方法。
  • ProxySubject:代理类,持有对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行。
  • Client:客户端类。

代理模式的简单实现

简单起见,我们这里举一个代购的例子:

抽象主题类(Subject)

抽象主题类具有真实主题类和代理的共同接口方法,在这里就是购买。

public interface Shopping {
    //购买
    void buy();
}
真实主题类(RealSubject)

这个消费者就是被代理的对象,实现了Shopping接口提供的 buy()方法:

public class Customer implements Shopping {
    @override
    public void buy(){
        System.out.println("购买");
    }
}
代理类(ProxySubject)

代理类同样也要实现Shopping接口,并且要持有被代理者,在buy()方法中调用了被代理者的buy()方法:

public class Purchasing implements Shopping {
    private Shopping mShoping;
    public Purchasing(Shopping shopping){
        mShopping = shopping
    }
    
    @Override
    public void buy() {
        mShoping.buy();
    }
}
客户端类(Client)
public class Client {
    public static void main(String[] args) {
        //创建顾客
        Shopping customer = new Customer();
        //创建代购者并将customer作为构造函数传参
        Shopping purchasing = new Purchasing(customer);
        Purchasing.buy();
    }
}

看完客户端类的代码,其实也是很好理解,就是代理类包含了真实主题类(被代理者),最终调用的都是真实主题类(被代理者)实现的方法.

动态代理的简单实现

从编码的角度来说,代理模式分为静态代理和动态代理。静态代理,在代码运行前就已经存在了代理类的class编译文件,而动态代理则是在代码运行时通过反射来动态的生成代理类的对象,并确定到底来代理谁。Java提供了动态的代理接口InvocationHandler,实现该接口需要重写invoke()方法。下面我们在上面静态代理的例子上做修改:

//创建动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicPurchasing implements InvocationHandler{
    private Object obj;
    public DynamicPurchasing(Object obj){
        this.obj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
        Object result = method.invoke(obj, args);
        return result;
    }
}
//客户端类
import java.lang.reflect.Proxy;
public class Client {
    public static void main(string[] args){
        //创建被代理用户
        Shopping customer = new Customer();
        //创建动态代理
        DynamicPurchasing mDynamicPurchasing=new DynamicPurchasing(customer);
        //创建customer的ClssLoader
        ClassLoader loader = customer. getClass().getClassLoader();
        //动态创建代理类
        Shopping purchasing=(Shopping) Proxy.newProxyInstance(loader,new Class[]{Shopping.class},mDynamicPurchasing);
        purchasing.buy();
    }
}

参考文章:http://liuwangshu.cn/tags/设计模式/
仅做学习记录,如有侵权,请联系删除。

posted @ 2021-12-18 22:47  夏虫语冰&  阅读(64)  评论(0)    收藏  举报