单例模式
装饰者模式
在讲装饰者模式之前,先说下“开闭原则”
定义:不修改源代码的情况下改变这个模块的行为。
案例:
如果界面类LoginForm需要将CircleButton改为RctangleButton来使用,则需要修改界面类的源代码,修改按钮类的类名以及dispaly()方法。
public class Demo {
public static void main(String[] args) throws IOException {
LoginForm a=new LoginForm(new RectangleButton());
a.display();
//LoginForm a=new LoginForm(new CircleButton());
//a.display();
}
}
class CircleButton extends AbstractButton
{
public void display(){
System.out.println("圆形按钮");
}
}
class RectangleButton extends AbstractButton
{
public void view(){
System.out.println("矩形按钮");
}
}
class LoginForm
{
private CircleButton button;
public void display(){
button.display();
}
/*
若要调用RectangleButton类,则代码变为:
private RectangleButton button;
public void display(){
button.view();
}
这样类的属性以及方法都被修改过了,不符合“开闭原则”
*/
}
解决方案:采用面向抽象类编程。
实现代码如下:
import java.io.*;
import java.util.*;
abstract class AbstractButton
{
public abstract void display();
}
class CircleButton extends AbstractButton
{
public void display(){
System.out.println("圆形按钮");
}
}
class RectangleButton extends AbstractButton
{
public void display(){
System.out.println("矩形按钮");
}
}
class LoginForm
{
private AbstractButton button;
LoginForm(AbstractButton button){
this.button=button;
}
public void display(){
button.display();
}
}
1、装饰模式是一种用于替代继承的技术,它通过一种无需定义子类的方式给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。
2、用户可以根据需要增加新的具体构建类和具体装饰类,在使用时再对其进行组合,原有的具体构建类和具体装饰类代码无序改变,符合“开闭原则”。
为什么需要装饰者模式:
比如说我有鸡肉汉堡与牛肉汉堡,客户现在需要鸡肉与牛肉混在一起的汉堡,如何办呢?采用继承的方式可以解决这个问题,但是如果程序中有很多种单独的肉类汉堡,而且客户需要多种组合呢?结果就是各种单独类的子类太多,有爆炸式增长的危险。
另外如果具体构建类为final,即不能继承,这时候就可以装饰模式来动态扩展具体构建类的功能。
代码如下所示:
import java.io.*;
import java.util.*;
interface HB
{
public void operation();
}
class JHB implements HB
{
public void operation(){
System.out.print("鸡肉汉堡");
}
}
class Decorator implements HB
{
private HB hb;
Decorator(HB hb){
this.hb=hb;
}
public void operation(){
hb.operation();
}
}
class JNHB extends Decorator
{
JNHB(HB hb){
super(hb);
}
public void display(){
System.out.println("\"鸡肉+牛肉\"汉堡");
}
}
class Demo
{
public static void main(String[] args){
HB h=new JHB();
JNHB jnhb=new JNHB(h);
jnhb.display();
}
}
二、策略模式
为什么使用策略模式:
例如:一个类中有许多种的查找方法,将这些方法写入到同一个方法中,客户通过传入参数(if...else)的语句来调用不同的方法,时间上的浪费。且,当需要添加一个新的功能时,将修改类中的代码,添加新的方法,不符合“开闭原则”
策略模式适用于:
1、如果在一个系统里有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为,符合“单一职责原则”
2、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。此时使用策略模式,把这些行为转移到相应的具体策略类中,就可以避免使用难以维护的多重条件选择语句,并且体现面向对象设计的概念。
类图如下:
这里说下聚合等关系。在UML中,依赖关系一般是一个对象是另一个对象某个方法中的参数;如果A对象的方法参数是B对象,且A对象的属性中也有B对象,那么A与B 的关系就考虑聚合与组合。关联关系一般就是A中属性有B。
三、观察者模式
为什么使用观察者模式?
一个对象的改变将 导致其他一个或多个对象发生改变,而不知道具体有多少对象将发生改变。
类图如下:
代码如下所示:
public class Subject {
private String msg="老板没来!";
private List list=new ArrayList();
/**
* 添加观察者
* @param observer
*/
public void add(Observer observer){
list.add(observer);
}
/**
* 删除观察者
* @param observer
*/
public void delete(Observer observer){
list.remove(observer);
}
/**
* 改变状态
* @param msg
*/
public void setMsg(String msg){
this.msg=msg;
}
/**
* 获取通知消息
* @return
*/
public String getMsg(){
return msg;
}
/**
* 通知所有的观察者状态变化
*/
public void notifyObservers(){
for(int i=0;i list.get(i).update();
}
}
}
public class Observer {
private Subject subject;
private String msg;
private String name;
public Observer(Subject subject,String name){
this.subject = subject;
this.name=name;
}
/**
* 获取更新数据
*/
public void update(){
System.out.println(name+"得到通知,内容是:"+subject.getMsg());
}
}
public static void main(String[] args) {
Subject subject = new Subject();
Observer observer1 = new Observer(subject,"chen");
Observer observer2 = new Observer(subject,"zou");
subject.add(observer1);
subject.add(observer2);
subject.setMsg("老板来了,快干活!");
subject.notifyObservers();
}
最好抽象与接口类内不要定义属性,放到子类中去定义最好。
看股票和看NBA观察者类似,所以用了抽象类而不是接口。但是如果具体观察者是风马牛不相及的类,但它们都需要根据通知者的通知来作出update的操作,这时候就可以用接口来定义观察者。例如:
interface Observer{
void update();
}
中介者模式
为什么使用?
适用的环境如下:
类图如下所示:
具体类1通过method2()向中介者发出信息,中介者通过operation()方法向另一个具体类2发出具体类1发出的信息。中介者类与具体类是双向关联的,与有关联关系的观察者模式的类图非常相似,但是调用的顺序不同,功能也不同。就是operation()这个方法,观察者模式是将消息发给全体具体类,而中介者模式是发给某一具体类、部分具体类或者全体具体类。具体类中的函数功能也不一样,观察者模式中就没有给目标类发送消息的。
具体代码如下所示:
模板方法模式
顾名思义,就是将所有方法按顺序放入一个模板方法中
模式适用的情况:
提取类库中的公共行为,将公共行为放在父类中,而通过其子类来实现不同的行为
缺点就是每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大。
类图:(先做面粉,后做水饺)
代码如下:
import java.io.*;
import java.util.*;
abstract class Test
{
void templateMethod(){
operation1();
operation2();
}
abstract void operation1();
abstract void operation2();
}
class ConcreteTest extends Test
{
public void operation1(){
System.out.println("先做面粉");
}
public void operation2(){
System.out.println("再做水饺");
}
}
public class Demo
{
public static void main(String[] args) throws IOException {
Test t=new ConcreteTest();
t.templateMethod();
}
}
备忘录模式
使用情况:保存一个对象在某一个时刻的状态或部分状态,这样以后需要时它能够恢复到先前的状态
类图:
其中,Originator原发器 Memento备忘录 Caretaker负责人
运行原理:负责人先从原发器那里保存一个备忘录对象,当原发器的状态改变而需要返回到某一个状态时候,就可以调用负责人来恢复它之前的状态。
代码如下所示:
import java.io.*;
import java.util.*;
class Originator
{
private String state;
public void setState(String state){
this.state=state;
}
public String getState(){
return state;
}
public Memento createMemento(){
return new Memento(state);
}
public void restoreMemento(Memento memento){
this.state=memento.getState();
}
}
class Caretaker
{
private Memento memento;
public void setMemento(Memento memento){
this.memento=memento;
}
public Memento getMemento(){
return memento;
}
}
class Memento
{
private String state;
Memento(String state){
this.state=state;
}
public void setState(String state){
this.state=state;
}
public String getState(){
return state;
}
}
public class Demo
{
public static void main(String[] args) throws IOException {
Caretaker c=new Caretaker();
Originator o = new Originator();
o.setState("chen");
c.setMemento(o.createMemento());
System.out.println("初始状态为:"+o.getState());
System.out.println(".....................");
o.setState("zou");
System.out.println("将状态更新为:zou");
System.out.println(".....................");
o.restoreMemento(c.getMemento());
System.out.println("恢复后的状态为:"+o.getState());
}
}
1、与中介者比较像,但是中介者的接收者与发送者都是继承都一个父类,而命令模式两者不同类。
2、当系统需要支持命令的撤销与重新执行时候就可以用到命令模式。
3、Invoke调用Command的execute()方法,execute()调用operation()方法,完成信息的传递。
类图:
代码如下:
import java.io.*;
import java.util.*;
abstract class Command
{
abstract void execute();
}
class Invoke
{
private Command command;
public void setCommand(Command command){
this.command=command;
}
public void call(){
command.execute();
}
}
class Receiver
{
public void operation(){
System.out.println("接收到信息");
}
}
class ConcreteCommand extends Command
{
private Receiver receiver;
public void execute(){
receiver.operation();
}
public ConcreteCommand(){
receiver=new Receiver();
}
}
public class Demo
{
public static void main(String[] args) throws IOException {
Command c=new ConcreteCommand();
Invoke i=new Invoke();
i.setCommand(c);
i.call();
}
}
组合模式
模式动机:组合模式描述了如何将容器对象和叶子对象进行递归组合,使得用户在使用时无需对它们进行区分,可以一致地对待容器对象和叶子对象。
类图:
代码如下:
import java.io.*;
import java.util.*;
abstract class Composite
{
abstract void add(Composite composite);
abstract void remove(Composite composite);
abstract void operation();
abstract Composite getChild(int i);
}
class Leaf extends Composite
{
public void add(Composite composite){
try
{
throw new Exception();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void remove(Composite composite){
try
{
throw new Exception();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public Composite getChild(int i){
try
{
throw new Exception();
}
catch (Exception e)
{
e.printStackTrace();
}
return new ConcreteComposite();
}
public void operation(){
System.out.println("这是叶子节点");
}
}
class ConcreteComposite extends Composite
{
List list=new ArrayList();
public void add(Composite composite){
list.add(composite);
}
public void remove(Composite composite){
list.remove(composite);
}
public Composite getChild(int i){
return list.get(i);
}
public void operation(){
for(Composite c:list){
c.operation();
}
}
}
public class Demo
{
public static void main(String[] args) throws IOException {
Composite c1=new Leaf();
Composite c2=new Leaf();c2.add(c1);
Composite c3=new Leaf();
Composite c4=new ConcreteComposite();
Composite c5=new ConcreteComposite();
c4.add(c2);c4.add(c3);c4.operation();
System.out.println("............................................");
c5.add(c1);c5.add(c4);c5.operation();
}
}
外观模式
模式动机:门户网站
1、迪米特法则要求每一个对象与其他对象的相互作用均是短程的而不是长程的
2、实现了子系统与客户之间的松耦合关系
常见的用途:
1、数据库的一般都有Connection以及Statement对象,将这两个对象及其相应的方法封装在外观类中。。。
2、门户网站的应用。
与模板方法模式的区别:
模板类没有调用子类的方法,而是自己的方法按顺序在模板方法中被调用而已。
类图:
做到现在,代码已经不重要了,类图已经标明的很明确了,代码就是分分钟的事情。
原型模式
建造者模式
优点:客户端可以不用知道产品内部的组成细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
注意:客户端也可以不通过建造者类来创建产品,因为产品本身世可以直接创建的
适用环境:
1、需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性
2、需要生成的产品需要指定其生成顺序
3、对象的创建过程独立于创建该对象的类。否则,就是模板方法了。
类图:
工厂方法模式
工厂方法出产产品,建造者组装零件成产品
类图:
享元模式
模式的优点:
1 它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份*(每new一个对象内存都要另外分配一个地址,耗费内存)。
2 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
类图:
代码略
代理模式
模式动机:
某人要找对象,但是由于某些原因不能直接去找,于是委托一个中介机构去完成这一过程,如婚姻介绍所,就是一个代理。
优点:
1 能够协调调用者和被调用者,在一定程度上降低了系统的耦合
2 远程代理使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算能力与处理速度,可以快速响应并处理客户端的请求
类图(数学运算代理类)