常用设计模式复习
单例
定义
保证一个类仅有一个实例,并提供一个访问它的全局访问点。

写法
单例模式有多种写法,各有利弊:
- 饿汉模式(预加载)
private class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){
}
public static Singleton get Instance() {
return instance;
}
}
这种方式在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快。 这种方式基于类加载机制避免了多线程的同步问题,但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到懒加载的效果。
- 懒汉模式(懒加载)
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/设计模式/
仅做学习记录,如有侵权,请联系删除。

浙公网安备 33010602011771号