作为一名Java开发者,了解并学习一些常用的设计模式是很有必要的,不常用的就可以先不管它了,要用到的时候再去了解,现在学习了解一下常用的几种设计模式,单例模式、工厂模式、建造模式、适配器模式、代理模式、观察者模式
一、单例模式
单例模式的主要目的是使内存中始终保持一个对象,Demo如下:
public class Singleton {
//将自身的实例对象设置为一个属性,并加上Static和final修饰符
private static final Singleton instance = new Singleton();
//将构造方法设置成私有形式
private Singleton() {
}
//通过一个静态方法向外界提供这个类的实例
public static Singleton getInstance() {
return instance;
}
}
这样每次都使用Singleton.getInstance()方法来获得一个对象,内存中始终就保持着一个对象,这就是单例模式。
二、工厂模式
工厂模式主要目的是统一提供实例对象的引用,Demo如下:
public class Factory {
public ClassesDao getClassesDao() {
ClassesDao cd = new ClassesDaoImpl();
return cd;
}
}
interface ClassesDao {
public String getClassesName();
}
class ClassesDaoImpl implements ClassesDao {
public String getClassesName() {
System.out.println("A班");
}
}
class test {
public static void main(String[] args) {
Factory f = new Factory();
f.getClassesDao().getClassesName();
}
}
这样子,使用工厂来获得对象实例的引用,即每次都使用f.getClassesDao()获得对象实例的引用。
三、建造模式
将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。
public interface Builder {
// 创建部件A 比如创建汽车车轮
void buildPartA();
// 创建部件B 比如创建汽车方向盘
void buildPartB();
// 创建部件C 比如创建汽车发动机
void buildPartC();
// 返回最后组装成品结果 (返回最后装配好的汽车)
// 成品的组装过程不在这里进行,而是转移到下面的Director类别中进行。
// 从而实现了解耦过程和部件
Product getResult();
}
public class Director {
private Builder builder;
public Director( Builder builder ) {
this.builder = builder;
}
// 将部件partA partB partC最后组成复杂对象
// 这里是将车轮 方向盘和发动机组装成汽车的过程
public void construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
}
}}
这样就将产品的内部表象和产品的生成过程分割开了,从而使一个建造过程生成具有不同的内部表象的产品对象。
四、适配器模式
把一个类的接口变换为客户端所期待的另一种接口,从而使原本因接口不匹配造成无法一起工作的两个雷可以一起工作,适配器可以根据参数返还一个合适的实例给客户端。
public interface IRoundPeg {
public void insertIntoHole(String msg);
}
public interface ISquarePeg {
public void insert(String str);
}
public class PegAdapter implements IRoundPeg, ISquarePeg {
private RoundPeg roundPeg;
private SquarePeg squarePeg;
// 构造方法
public PegAdapter(RoundPeg peg) {
this.roundPeg = peg;
}
// 构造方法
public PegAdapter(SquarePeg peg) {
this.squarePeg = peg;
}
public void insert(String str) {
roundPeg.insertIntoHole(str);
}
public void insertIntoHole(String str) {
SquarePeg.insert(str);
}
}
这样就可以根据参数来返还IRoundPeg或者是ISquarePeg实例给客户端了。
五、代理模式
代理模式有两种实现方式,一种是静态代理,另一种是动态代理,各大框架都喜欢用动态代理。
静态代理
public interface Subject {
void visit();
}
//实现Subject接口的两个类
public class RealSubject implements Subject {
private String name = "byhieg";
@Override
public void visit() {
System.out.println(name);
}
}
public class ProxySubject implements Subject{
private Subject subject;
public ProxySubject(Subject subject) {
this.subject = subject;
}
@Override
public void visit() {
subject.visit();
}
}
//然后如下方式调用
public class Client {
public static void main(String[] args) {
ProxySubject subject = new ProxySubject(new RealSubject());
subject.visit();
}
}
通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。但是也有缺点,每一个代理类都必须实现一遍委托类(也就是realsubject)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。
动态代理
动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy
,通过固定的规则生成。
接上面代码
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(object, args);
return result;
}
}
然后创建动态代理对象
Subject realSubject = new RealSubject();
DynamicProxy proxy = new DynamicProxy(realSubject);
ClassLoader classLoader = realSubject.getClass().getClassLoader();
Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new Class[]{Subject.class}, proxy);
subject.visit();
六、观察者模式
观察者模式又称为发布/订阅(Publish/Subscribe)模式,因此我们可以用报纸期刊的订阅来形象的说明:
报社方负责出版报纸.
你订阅了该报社的报纸,那么只要报社发布了新报纸,就会通知你,或发到你手上.
如果你不想再读报纸,可以取消订阅,这样,报社发布了新报纸就不会再通知你.
理解其实以上的概念,就可以理解观察者模式,观察者模式中有主题(Subject)和观察者(Observer),分别对应报社和订阅用户(你).观察者模式定义了对象之间的一对多的依赖关系,这样,当"一"的一方状态发生变化时,它所依赖的"多"的一方都会收到通知并且自动更新.
package com.wang.observer;
//主题接口
interface Subject {
//添加观察者
void addObserver(Observer obj);
//移除观察者
void deleteObserver(Observer obj);
//当主题方法改变时,这个方法被调用,通知所有的观察者
void notifyObserver();
}
package com.wang.observer;
interface Observer {
//当主题状态改变时,会将一个String类型字符传入该方法的参数,每个观察者都需要实现该方法
public void update(String info);
}
package com.wang.observer;
import java.util.ArrayList;
import java.util.List;
public class TeacherSubject implements Subject {
//用来存放和记录观察者
private List<Observer> observers=new ArrayList<Observer>();
//记录状态的字符串
private String info;
@Override
public void addObserver(Observer obj) {
observers.add(obj);
}
@Override
public void deleteObserver(Observer obj) {
int i = observers.indexOf(obj);
if(i>=0){
observers.remove(obj);
}
}
@Override
public void notifyObserver() {
for(int i=0;i<observers.size();i++){
Observer o=(Observer)observers.get(i);
o.update(info);
}
}
//布置作业的方法,在方法最后,需要调用notifyObserver()方法,通知所有观察者更新状态
public void setHomework(String info){
this.info=info;
System.out.println("今天的作业是"+info);
this.notifyObserver();
}
}
package com.wang.observer;
public class StudentObserver implements Observer {
//保存一个Subject的引用,以后如果可以想取消订阅,有了这个引用会比较方便
private TeacherSubject t;
//学生的姓名,用来标识不同的学生对象
private String name;
//构造器用来注册观察者
public Student(String name,Teacher t) {
this.name=name;
this.t = t;
//每新建一个学生对象,默认添加到观察者的行列
t.addObserver(this);
}
@Override
public void update(String info) {
System.out.println(name+"得到作业:"+info);
}
}
测试:
package com.wang.observer;
public class TestObserver {
public static void main(String[] args) {
TeacherSubject teacher=new TeacherSubject();
StudentObserver zhangSan=new StudentObserver("张三", teacher);
StudentObserver LiSi=new StudentObserver("李四", teacher);
StudentObserver WangWu=new StudentObserver("王五", teacher);
teacher.setHomework("第二页第六题");
teacher.setHomework("第三页第七题");
teacher.setHomework("第五页第八题");
}
}
打印结果:
今天的作业是第二页第六题
张三得到作业:第二页第六题
李四得到作业:第二页第六题
王五得到作业:第二页第六题
今天的作业是第三页第七题
张三得到作业:第三页第七题
李四得到作业:第三页第七题
王五得到作业:第三页第七题
今天的作业是第五页第八题
张三得到作业:第五页第八题
李四得到作业:第五页第八题
王五得到作业:第五页第八题
从打印结果看,每当老师布置作业的状态改变,就会通知每一个学生.以上就是一个简单的观察者模式的实现.
推荐大家一个Java的学习网站:Java知识学习网,Java资料下载,Java学习路线图,网址:https://www.java1010.com