博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式实践与总结(持续更新中)
阅读量:3939 次
发布时间:2019-05-23

本文共 5365 字,大约阅读时间需要 17 分钟。

概述

基本含义不再详述

分类:一般根据目的划分为三类:创建型模式、结构型模式、行为型模式

  • 创建型模式:解决“如何创建对象,将对象创建与使用分离”,包括单例、原型、工厂方法、抽象工厂、建造者模式
  • 结构型模式:解决“如何将类或对象按某种布局组成更大的结构”,包括代理、适配器、桥接、装饰、外观、享元、组合
  • 行为型模式:解决“类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责”,包括模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器

几大原则:

  • 开闭原则:软件实体应当对扩展开放,对修改关闭,即当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求
  • 里氏替换原则:继承必须确保超类所拥有的性质在子类中仍然成立(几维鸟不是鸟)
  • 依赖倒置原则:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象,核心即为面向接口编程
  • 单一职责原则:对象不应该承担太多职责,核心就是控制类的粒度大小、将对象解耦、提高其内聚性
  • 接口隔离原则:一个类对另一个类的依赖应该建立在最小的接口上,即接口中应不包含接口的实现者不需要的抽象方法
  • 迪米特法则:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性
  • 合成复用法则:软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现

单例模式

应用场景:

  • 某类只要求生成一个对象的时候,如一个班中的班长、每个人的身份证号等;
  • 当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web中的配置对象、数据库的连接池等;
  • 当某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。

实现代码:

public class Singleton {
private static Singleton singleton=null; //避免在外部被实例化 private Singleton(){
}; public static synchronized Singleton getSingleton(){
if(singleton==null){
singleton=new Singleton(); }else{
System.out.println("已经被实例化了"); } return singleton; }}

原型模式

含义:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。

应用场景:

  • 对象之间相同或相似,即只是个别的几个属性不同的时候;
  • 对象的创建过程比较麻烦,但复制比较简单的时候。

分类:

  • 浅拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象.
  • 深拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制.

实现代码:

public class ProtoType implements Cloneable{
private int id; private String name; private AccProtoType accProtoType; public ProtoType(){
}; public Object clone() throws CloneNotSupportedException {
return (ProtoType)super.clone(); }}

测试代码:

//原型模式测试        ProtoType p1=new ProtoType();        p1.setId(1);        p1.setName("我是本体");        AccProtoType accProtoType=new AccProtoType(11);        p1.setAccProtoType(accProtoType);        ProtoType p2= (ProtoType) p1.clone();        System.out.println(p1.getId()+p1.getName()+p1.getAccProtoType().id);        System.out.println(p2.getId()+p2.getName()+p2.getAccProtoType().id);        System.out.println(p1==p2);        p1.setId(2);        p1.setName("我是copy");        accProtoType.id=22;        System.out.println(p1.getId()+p1.getName()+p1.getAccProtoType().id);        System.out.println(p2.getId()+p2.getName()+p2.getAccProtoType().id);

结果:

在这里插入图片描述
解释一下最后两行的后两个字段,因为浅复制只复制了引用,p1在修改name属性时,由于name为String类型,无法修改,所以虚拟机只能在内存中新建一个String,值为“我是copy”,并将该引用指向p1,所以p2的引用还是原引用,值也就仍然时“我是本体”,而修改accProtoType的id属性时,并没有改变引用,所以p1和p2中的accProtoType仍然是同一个对象,自然属性值也相同。

深克隆:AccProtoType中也实现clone()方法。

观察者模式:

指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

优点:解耦合

缺点:依赖关系并没有完全解除,可能出现循环引用。当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

三要素:事件、事件源、监听者

  • 事件
    一般继承EventObject类,所以在定义事件时,必须要有形参为事件源的构造器,实现事件与事件源的绑定;另外,当有多种事件时,不必定义事件的接口或抽象类,因为可以使用EventObject
  • 事件源
    关联事件与监听者的中间组件,要有保存事件与监听者对应关系的成员变量(Map),要有增添、删除监听者的方法,要有通知监听者的方法。
  • 监听者
    多个监听者需要实现同一接口,接口中要定义对事件的处理方法,每个监听者对其重写

示例程序:

BellEvent类:

import java.util.EventObject;public class BellEvent extends EventObject {
public BellEvent(EventSource eventSource) {
super(eventSource); }}

ExamEvent类:

import java.util.EventObject;public class ExamEvent extends EventObject {
public ExamEvent(EventSource eventSource){
super(eventSource); }}

EventSource类:

import java.util.*;public class EventSource {
private Map
> listerMap=new HashMap
>(); public void addListener(EventObject eventObject,EventLister lister){
if(listerMap.get(eventObject.getClass().getSimpleName())==null){
HashSet set=new HashSet
(); set.add(lister); listerMap.put(eventObject.getClass().getSimpleName(), set); }else {
listerMap.get(eventObject.getClass().getSimpleName()).add(lister); } } public void removeListener(BellEvent event,EventLister lister){
listerMap.get(event.getClass().getSimpleName()).remove(lister); } public void start(EventObject eventObject){
System.out.println("开始通知"+eventObject.getClass().getSimpleName()+"事件的监听者"); notify(eventObject); } private void notify(EventObject eventObject){
Iterator
iterator=listerMap.get(eventObject.getClass().getSimpleName()).iterator(); while (iterator.hasNext()){
iterator.next().handle(); } }}

Listener接口:

public interface EventListener {
public void handle();}

TeacherEventListener类:

public class TeacherEventListener implements EventLister {
@Override public void handle() {
System.out.println("老师去上课了"); }}

StudentEventListener类:

public class StudentEventListener implements EventLister {
@Override public void handle() {
System.out.println("学生开始考试"); }}

测试类:

public class main {
public static void main(String[] args) {
EventSource eventSource=new EventSource(); BellEvent bellEvent=new BellEvent(eventSource); ExamEvent examEvent=new ExamEvent(eventSource); eventSource.addListener(bellEvent,new TeacherEventListener()); eventSource.addListener(examEvent,new StudentEventListener()); eventSource.start(bellEvent); eventSource.start(examEvent); }}

效果:

开始通知BellEvent事件的监听者老师去上课了开始通知ExamEvent事件的监听者学生开始考试

转载地址:http://trzwi.baihongyu.com/

你可能感兴趣的文章
win7 文件删除后要刷新后才会消失
查看>>
AAC经过RTP格式封装后的格式。
查看>>
将es打包成pes时,处理PTS和DTS的方法
查看>>
做个合格的程序员
查看>>
CString.Format大全 格式化时间戳等无符号整数
查看>>
对于位域在结构体中的比特序
查看>>
linux网络编程之-----多播(组播)编程(转)
查看>>
解析RTP流for mpeg4
查看>>
RTP封装h264
查看>>
利用ffmpeg在服务器端合成视频
查看>>
Epoll模型详解
查看>>
C++面试题锦集
查看>>
poll使用
查看>>
多进程和多线程的优劣
查看>>
epoll使用详解
查看>>
wireshark学习随手记
查看>>
解决git上传错误
查看>>
Git学习笔记
查看>>
pack(1)的使用
查看>>
STL实现的底层数据结构简介
查看>>