设计模式简介

一、设计模式简介

设计模式(Design Pattern)描述了软件开发过程中若干重复出现的问题的解决方案,这些方案不是由过程、算法等底层程序构造实体实现,而是由软件系统中类与类之间或不同类的对象之间的共生关系组成。

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用,是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

学习设计模式可以帮助软件设计人员学习、重用前人的经验和成果。

在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。

四位作者合称 GOF(四人帮,全拼 Gang of Four)。他们所提出的设计模式主要是基于以下的面向对象设计原则:

1、对接口编程而不是对实现编程。

2、优先使用对象组合而不是继承。

另外还有J2EE设计模式。

二、设计模式分类

1、GOF设计模式分为三大类共23种:

(1)创建型模式,共五种:

工厂模式(Factory Pattern)、抽象工厂模式(Abstract Factory Pattern)、单例模式(Singleton Pattern)、建造者模式(Builder Pattern)、原型模式(Prototype Pattern)

这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

(2)结构型模式,共七种:

适配器模式(Adapter Pattern)、桥接模式(Bridge Pattern)、组合模式(Composite Pattern)装饰器模式(Decorator Pattern)、外观模式(Facade Pattern)、享元模式(Flyweight Pattern)、代理模式(Proxy Pattern)

这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。

(3)行为型模式,十一种:

责任链模式(Chain of Responsibility Pattern)、命令模式(Command Pattern)、解释器模式(Interpreter Pattern)、迭代器模式(Iterator Pattern)、中介者模式(Mediator Pattern)备忘录模式(Memento Pattern)、观察者模式(Observer Pattern)、状态模式(State Pattern)策略模式(Strategy Pattern)、模板模式(Template Pattern)、访问者模式(Visitor Pattern)

这些设计模式特别关注对象之间的通信。

2、J2EE设计模式

MVC 模式(MVC Pattern)、业务代表模式(Business Delegate Pattern)、组合实体模式(Composite Entity Pattern)、数据访问对象模式(Data Access Object Pattern)、前端控制器模式(Front Controller Pattern)、拦截过滤器模式(Intercepting Filter Pattern)、服务定位器模式(Service Locator Pattern)、传输对象模式(Transfer Object Pattern)

这些设计模式特别关注表示层。这些模式是由 Sun Java Center 鉴定的。

3、设计模式之间的关系

三、设计模式的六大原则

1、开闭原则(Open Close Principle)

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

3、依赖倒转原则(Dependence Inversion Principle)

这个是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。强调降低依赖,降低耦合。

5、迪米特法则(最少知道原则)(Demeter Principle)

一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

尽量使用合成/聚合的方式,而不是使用继承。

 

==============================================================================================================================

下面内容重新整理中。。。。。。

 

三、设计模式详解

设计模式之创建型模式

4、建造者模式(Builder)

工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性。

建造者模式将很多功能集成到一个类里,这个类可以创造出比较复杂的东西。所以与工厂类模式的区别就是:工厂类模式关注的是创建单个产品,而建造者模式则关注创建复合对象的多个部分。因此,是选择工厂类模式还是建造者模式,依实际情况而定。

以下代码只是一个简单的示例,没有使用接口,实际应用一般都会考虑使用接口,增强扩展性。

对象类

public class Person {
    
    private String head;
    
    private String body;
    
    private String foot;

    public String getHead() {
        return head;
    }

    public void setHead(String head) {
        this.head = head;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public String getFoot() {
        return foot;
    }

    public void setFoot(String foot) {
        this.foot = foot;
    }
    
}

建造者类

public class Builder {
    
    Person person;
    
    public Builder(){
        person = new Person();
    }
    
    public void buildHead(){
        person.setHead("头");
    }
    
    public void buildBody(){
        person.setBody("身体");
    }
    
    public void buildFoot(){
        person.setFoot("脚");
    }

}

测试类

public class BuilderTest {
    
    public static void main(String[] args) {
        Builder builder = new Builder();
        //开始建造对象
        builder.buildHead();
        builder.buildBody();
        builder.buildFoot();
        //获取到建造的对象
        Person person = builder.person;
    }
    
}

5、原型模式(Prototype)

原型模式虽然是创建型的模式,但是与工厂类模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。

简单原型类

public class ProtoType implements Cloneable{
    
    public Object clone() throws CloneNotSupportedException{
        ProtoType protoType = (ProtoType)super.clone();
        return protoType;
    }

}

编写一个原型类,只需要实现Cloneable接口(只是一个标志接口,表示该类是可复制的,否则会抛出CloneNotSupportedException异常),覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的。

复制又分为浅复制和深复制。

浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。

深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。

简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。

完整的原型类

public class ProtoType implements Cloneable, Serializable{
    
    private static final long serialVersionUID = 1L;

    public String str;
    
    public SerializableObject obj;
    
    //浅复制
    public Object simpleClone() throws CloneNotSupportedException{
        ProtoType protoType = (ProtoType)super.clone();
        return protoType;
    }
    
    //深复制
    public Object deepClone() throws IOException, ClassNotFoundException{
        //写入当前对象的二进制流
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        //读出二进制产生的新对象
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }

}

class SerializableObject implements Serializable{

    private static final long serialVersionUID = 1L;
    
}

测试类

public class Test {
    
    public static void main(String[] args) {
        ProtoType protoType = new ProtoType();
        System.out.println(protoType);//com.wb.pd.原型.ProtoType@15db9742
        try {
            ProtoType protoType1 = (ProtoType) protoType.simpleClone();
            System.out.println(protoType1);//com.wb.pd.原型.ProtoType@6d06d69c
            ProtoType protoType2 = (ProtoType) protoType.deepClone();
            System.out.println(protoType2);//com.wb.pd.原型.ProtoType@eed1f14
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
}

设计模式之结构型模式

对象的适配器模式是各种模式的起源

1、适配器模式(Adapter)

适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。

主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。

(1)类的适配器模式

源类

public class Source {
    
    public void method1(){
        System.out.println("这是方法1");
    }

}

目标接口

public interface TargetAble {
    
    //与源类中的方法相同
    public void method1();
    
    //新类中的方法
    public void method2();

}

适配器

public class Adapter extends Source implements TargetAble{

    @Override
    public void method2() {
        System.out.println("这是方法2");
    }
    
}

测试类

public class Test {

    public static void main(String[] args) {
        TargetAble targetAble = new Adapter();
        targetAble.method1();
        targetAble.method2();
    }

}

这样TargetAble接口的实现类就具有了Source类的功能。

(2)对象的适配器模式

基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。

适配器

public class Adapter implements TargetAble{
    
    private Source source;
    
    public Adapter(Source source) {
        this.source = source;
    }

    @Override
    public void method1() {
        source.method1();
    }
    @Override
    public void method2() {
        System.out.println("这是方法2");
    }
    
}

测试类

public class Test {

    public static void main(String[] args) {
        Source source = new Source();
        TargetAble targetAble = new Adapter(source);
        targetAble.method1();
        targetAble.method2();
    }

}

(3)接口的适配器模式

有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显比较浪费时间,因为并不是所有的方法都是我们需要的,有时只需要某一些方法,为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,并实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。

源接口

public interface SourceAble {
    
    public void method1();
    
    public void method2();

}

抽象类

public abstract class Adapter implements SourceAble{

    @Override
    public void method1() {}

    @Override
    public void method2() {}
    
}

目标类

public class Target extends Adapter{

    @Override
    public void method1() {
        System.out.println("这是方法1");
    }
    
}

测试类

public class Test {

    public static void main(String[] args) {
        SourceAble sourceAble = new Target();
        sourceAble.method1();//这是方法1
        sourceAble.method2();//无输出
    }

}

三种适配器模式的应用场景:

类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个适配器类,继承原有的类,实现新的接口即可。

对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个适配器类,持有原类的一个实例,在适配器类的方法中,调用实例的方法就行。

接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类作为适配器类,实现所有方法,我们写别的类的时候,继承该抽象类即可。

2、装饰模式(Decorator)

装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。

接口

public interface SourceAble {
    
    public void method();

}

被装饰类

public class Source implements SourceAble {

    @Override
    public void method() {
        System.out.println("这是被装饰者");
    }

}

装饰类

public class Decorator implements SourceAble {

    private SourceAble sourceAble;
    
    public Decorator(SourceAble sourceAble) {
        this.sourceAble = sourceAble;
    }
    
    @Override
    public void method() {
        System.out.println("前装饰");
        sourceAble.method();
        System.out.println("后装饰");
    }

}

测试类

public class Test {

    public static void main(String[] args) {
        SourceAble sourceAble1 = new Source();
        SourceAble sourceAble2 = new Decorator(sourceAble1);
        sourceAble2.method();
    }

}

装饰器模式的应用场景:

1、需要扩展一个类的功能。

2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)

缺点:产生过多相似的对象,不易排错!

3、代理模式(Proxy)

代理模式就是多一个代理类出来,替原对象进行一些操作。

接口

public interface SourceAble {
    
    public void method();

}

被代理类

public class Source implements SourceAble {

    @Override
    public void method() {
        System.out.println("这是被代理类");
    }

}

代理类

public class Proxy implements SourceAble {

    private Source source;
    
    public Proxy() {
        source = new Source();
    }
    
    @Override
    public void method() {
        before();
        source.method();
        after();
    }
    
    public void before(){
        System.out.println("代理前");
    }
    
    public void after(){
        System.out.println("代理后");
    }

}

测试类

public class Test {

    public static void main(String[] args) {
        SourceAble sourceAble = new Proxy();
        sourceAble.method();
    }

}

代理模式的应用场景:

如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:

1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。

2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制,这种方法就是代理模式。

使用代理模式,可以将功能划分的更加清晰,有助于后期维护!

4、外观模式(Facade)

外观模式是为了解决类与类之间的依赖关系,将类与类之间的关系放在一个Facade类中,降低了类与类之间的耦合度,该模式中没有涉及到接口。

下面代码使用电脑来进行说明,cpu类,power类,disk类,都集成到computer类中,最后user类来调用。

局部类

public class Power {
    
    public void startUp(){
        System.out.println("电源启动了");
    }
    
    public void shutDown(){
        System.out.println("电源关闭了");
    }

}
public class CPU {
    
    public void startUp(){
        System.out.println("CPU启动了");
    }
    
    public void shutDown(){
        System.out.println("CPU关闭了");
    }

}
public class Disk {
    
    public void startUp(){
        System.out.println("硬盘启动了");
    }
    
    public void shutDown(){
        System.out.println("硬盘关闭了");
    }

}

整体类

public class Computer {
    
    private Power power;
    
    private CPU cpu;
    
    private Disk disk;
    
    public Computer(){
        power = new Power();
        cpu = new CPU();
        disk = new Disk();
    }
    
    public void startUp(){
        System.out.println("开始启动电脑");
        power.startUp();
        cpu.startUp();
        disk.startUp();
        System.out.println("电脑启动了");
    }
    
    public void shutDown(){
        System.out.println("开始关闭电脑");
        power.shutDown();
        cpu.shutDown();
        disk.shutDown();
        System.out.println("电脑关闭了");
    }

}

测试类

public class User {
    
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.startUp();
        System.out.println("==========");
        computer.shutDown();
    }

}

5、桥接模式(Bridge)

桥接模式就是把事物和其具体实现分开,使他们可以各自独立的变化。桥接的用意是:将抽象化与实现化解耦,使得二者可以独立变化,像我们常用的JDBC桥DriverManager一样,JDBC进行连接数据库的时候,在各个数据库之间进行切换,基本不需要动太多的代码,甚至丝毫不用动,原因就是JDBC提供统一接口,每个数据库提供各自的实现,用一个叫做数据库驱动的程序来桥接就行了。

接口

public interface SourceAble {
    
    public void method();

}

两个实现类

public class Source1 implements SourceAble {

    @Override
    public void method() {
        System.out.println("这是Source1");
    }

}
public class Source2 implements SourceAble {

    @Override
    public void method() {
        System.out.println("这是Source2");
    }

}

使用抽象类定义一个桥

public abstract class Bridge {
    
    private SourceAble sourceAble;
    
    public void method(){
        sourceAble.method();
    }

    public SourceAble getSourceAble() {
        return sourceAble;
    }

    public void setSourceAble(SourceAble sourceAble) {
        this.sourceAble = sourceAble;
    }
    
}

定义一个可实例化的桥

public class MyBridge extends Bridge{

    @Override
    public void method() {
        getSourceAble().method();
    }

}

测试类

public class Test {
    
    public static void main(String[] args) {
        Bridge bridge = new MyBridge();
        
        //调用第一个对象
        SourceAble sourceAble1 = new Source1();
        bridge.setSourceAble(sourceAble1);
        bridge.method();
        
        //调用第二个对象
        SourceAble sourceAble2 = new Source2();
        bridge.setSourceAble(sourceAble2);
        bridge.method();
    }

}

这样,就通过对Bridge类的调用,实现了对接口SourceAble的实现类Source1和Source2的调用。这就是桥接模式。

6、组合模式(Composite)

组合模式有时又叫部分-整体模式,在处理类似树形结构的问题时比较方便。

递归组合模式简称组合模式,通过对象递归组合,形成“对象树”,以表示“整体-部分”关系的层次结构。与体现继承性的“类树”结构不同。组合模式提供了一种构造结构复杂的大对象的手段。

组合模式中含有两种类型的对象:基元对象和组合对象。组合模式使基元对象和组合对象具有一致的使用方式。

使用场景:将多个对象组合在一起进行操作,常用于表示树形结构中,例如二叉树,数等。

public class TreeNode {
    
    private String name;
    
    private TreeNode parent;
    
    private Vector<TreeNode> childern = new Vector<TreeNode>();
    
    public TreeNode(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public TreeNode getParent() {
        return parent;
    }

    public void setParent(TreeNode parent) {
        this.parent = parent;
    }
    
    //添加子节点
    public void add(TreeNode node){
        childern.add(node);
    }
    
    //删除子节点
    public void remove(TreeNode node){
        childern.remove(node);
    }
    
    //获取子节点
    public String getChildern(){
        StringBuffer sbf = new StringBuffer();
        for (TreeNode treeNode : childern) {
            sbf.append(treeNode.name);
        }
        return sbf.toString();
    }

    @Override
    public String toString() {
        return "name="+name+",parent="+parent.name+",childern="+getChildern();
    }
    
}
public class Tree {
    
    TreeNode root = null;
    
    public Tree(String name){
        root = new TreeNode(name);
    }
    
    public static void main(String[] args) {
        Tree tree = new Tree("ROOT");
        TreeNode nodeA = new TreeNode("A");
        TreeNode nodeB = new TreeNode("B");
        TreeNode nodeC = new TreeNode("C");
        
        tree.root.setParent(nodeA);//添加父节点
        nodeB.add(nodeC);//添加子节点
        tree.root.add(nodeB);//添加子节点
        
        System.out.println(tree.root);
    }

}

7、享元模式(Flyweight)

享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。

一提到共享池,我们很容易联想到Java里面的JDBC连接池,想想每个连接的特点,我们不难总结出:适用于作共享的一些个对象,他们有一些共有的属性,就拿数据库连接池来说,url、driverClassName、username、password及dbname,这些属性对于每个连接来说都是一样的,所以就适合用享元模式来处理,建一个工厂类,将上述类似属性作为内部数据,其它的作为外部数据,在方法调用时,当做参数传进来,这样就节省了空间,减少了实例的数量。

通过连接池的管理,实现了数据库连接的共享,不需要每一次都重新创建连接,节省了数据库重新创建的开销,提升了系统的性能!

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;

public class ConnectionPool {
    
    private Vector<Connection> pool;
    
    //公有属性
    private String url = "jdbc:mysql://localhost:3306/test";  
    private String username = "root";  
    private String password = "123456";  
    private String driverClassName = "com.mysql.jdbc.Driver";  
  
    private int poolSize = 100;  
    private static ConnectionPool instance = null;  
    Connection conn = null;  
  
    //构造方法,做一些初始化工作  
    private ConnectionPool() {  
        pool = new Vector<Connection>(poolSize);  
        for (int i = 0; i < poolSize; i++) {  
            try {  
                Class.forName(driverClassName);  
                conn = DriverManager.getConnection(url, username, password);  
                pool.add(conn);  
            } catch (ClassNotFoundException e) {  
                e.printStackTrace();  
            } catch (SQLException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
  
    //返回连接到连接池
    public synchronized void release() {
        pool.add(conn);
    }

    //返回连接池中的一个数据库连接
    public synchronized Connection getConnection() {
        if (pool.size() > 0) {
            Connection conn = pool.get(0);
            pool.remove(conn);
            return conn;
        } else {
            return null;
        }
    }
}

设计模式之行为型模式

1、策略模式(strategy)

  策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数。

统一接口

public interface ICalculator {
    
    public int calculate(String exp); 
    
}  

抽象类

public abstract class AbstractCalculator {  
    
    public int[] split(String exp,String opt){  
        String array[] = exp.split(opt);  
        int arrayInt[] = new int[2];  
        arrayInt[0] = Integer.parseInt(array[0]);  
        arrayInt[1] = Integer.parseInt(array[1]);  
        return arrayInt;  
    }  
    
}  

三个实现类

public class Minus extends AbstractCalculator implements ICalculator {  
      
    @Override  
    public int calculate(String exp) {  
        int arrayInt[] = split(exp,"-");  
        return arrayInt[0]-arrayInt[1];  
    }  
  
}  
public class Plus extends AbstractCalculator implements ICalculator {  
      
    @Override  
    public int calculate(String exp) {  
        int arrayInt[] = split(exp,"\\+");  
        return arrayInt[0]+arrayInt[1];  
    }  
    
}  
public class Multiply extends AbstractCalculator implements ICalculator {  
      
    @Override  
    public int calculate(String exp) {  
        int arrayInt[] = split(exp,"\\*");  
        return arrayInt[0]*arrayInt[1];  
    }  
    
} 

测试类

public class StrategyTest {  
      
    public static void main(String[] args) {  
        String exp = "2+8";  
        ICalculator cal = new Plus();  
        int result = cal.calculate(exp);  
        System.out.println(result);  
    }  
    
}  

策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可。

2、模板方法模式(Template Method)

一个抽象类中,有一个主方法,再定义1...n个方法,可以是抽象的,也可以是实际的方法,定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用。

抽象类

public abstract class AbstractCalculator {  
    
    //主方法,实现对本类其它方法的调用
    public final int calculate(String exp,String opt){  
        int array[] = split(exp,opt);  
        return calculate(array[0],array[1]);  
    }  
      
    //被子类重写的方法  
    abstract public int calculate(int num1,int num2);  
      
    public int[] split(String exp,String opt){  
        String array[] = exp.split(opt);  
        int arrayInt[] = new int[2];  
        arrayInt[0] = Integer.parseInt(array[0]);  
        arrayInt[1] = Integer.parseInt(array[1]);  
        return arrayInt;  
    }
    
} 

继承类

public class Plus extends AbstractCalculator {  
      
    @Override  
    public int calculate(int num1,int num2) {  
        return num1 + num2;  
    }
    
}

测试类

public class StrategyTest {  
      
    public static void main(String[] args) {  
        String exp = "8+8";  
        AbstractCalculator cal = new Plus();  
        int result = cal.calculate(exp, "\\+");  
        System.out.println(result);  
    }
    
}

3、观察者模式(Observer)

当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。

接口

public interface Observer {
    
    public void update(); 
    
} 

两个实现类

public class Observer1 implements Observer {  
      
    @Override  
    public void update() {  
        System.out.println("observer1 has received!");  
    } 
    
}  
public class Observer2 implements Observer {  
      
    @Override  
    public void update() {  
        System.out.println("observer2 has received!");  
    }  
  
}

接口

public interface Subject {  
    
    /*增加观察者*/  
    public void add(Observer observer);  
      
    /*删除观察者*/  
    public void del(Observer observer);  
      
    /*通知所有的观察者*/  
    public void notifyObservers();  
      
    /*自身的操作*/  
    public void operation();
    
}  

抽象实现类

public abstract class AbstractSubject implements Subject {  
      
    private Vector<Observer> vector = new Vector<Observer>();
    
    @Override  
    public void add(Observer observer) {  
        vector.add(observer);  
    }  
  
    @Override  
    public void del(Observer observer) {  
        vector.remove(observer);  
    }  
  
    @Override  
    public void notifyObservers() {  
        Enumeration<Observer> enumo = vector.elements();  
        while(enumo.hasMoreElements()){  
            enumo.nextElement().update();  
        }  
    }
    
} 

子类

public class MySubject extends AbstractSubject {  
      
    @Override  
    public void operation() {  
        System.out.println("update self!");  
        notifyObservers();  
    }  
  
}  

测试类

public class ObserverTest {  
      
    public static void main(String[] args) {  
        Subject sub = new MySubject();  
        sub.add(new Observer1());  
        sub.add(new Observer2());  
          
        sub.operation();  
    }  
  
}

MySubject类是主对象,Observer1和Observer2是依赖于MySubject的对象,当MySubject变化时,Observer1和Observer2必然变化。AbstractSubject类中定义着需要监控的对象列表,可以对其进行修改:增加或删除被监控对象,且当MySubject变化时,负责通知在列表内存在的对象。

4、迭代子模式(Iterator)

迭代器模式就是顺序访问聚集中的对象。一般来说,集合中非常常见,如果对集合类比较熟悉的话,理解本模式会十分轻松。这句话包含两层意思:一是需要遍历的对象,即聚集对象,二是迭代器对象,用于对聚集对象进行遍历访问。

下面代码模拟了一个集合

集合类接口

public interface Collection {  
    
    //迭代器
    public Iterator iterator();  
      
    //取得集合元素
    public Object get(int i);  
      
    //取得集合大小  
    public int size();
    
}  

集合类

public class MyCollection implements Collection {  
      
    public String string[] = {"A","B","C","D","E"};
    
    @Override  
    public Iterator iterator() {  
        return new MyIterator(this);  
    }  
  
    @Override  
    public Object get(int i) {  
        return string[i];  
    }  
  
    @Override  
    public int size() {  
        return string.length;  
    }  
    
}  

迭代器接口

public interface Iterator { 
    
    //前移  
    public Object previous();  
      
    //后移  
    public Object next();
    
    //是否有下一个元素
    public boolean hasNext();  
      
    //取得第一个元素  
    public Object first();  
    
}  

迭代器

public class MyIterator implements Iterator {  
      
    private Collection collection;
    
    private int pos = -1;  
      
    public MyIterator(Collection collection){  
        this.collection = collection;  
    }  
      
    @Override  
    public Object previous() {  
        if(pos > 0){  
            pos--;  
        }  
        return collection.get(pos);  
    }  
  
    @Override  
    public Object next() {  
        if(pos<collection.size()-1){  
            pos++;  
        }  
        return collection.get(pos);  
    }  
  
    @Override  
    public boolean hasNext() {  
        if(pos<collection.size()-1){  
            return true;  
        }else{  
            return false;  
        }  
    }  
  
    @Override  
    public Object first() {  
        pos = 0;  
        return collection.get(pos);  
    }  
  
} 

测试类

public class Test {  
      
    public static void main(String[] args) {  
        Collection collection = new MyCollection();  
        Iterator it = collection.iterator();  
          
        while(it.hasNext()){  
            System.out.println(it.next());  
        }  
    } 
    
}

MyCollection中定义了集合的一些操作,MyIterator中定义了一系列迭代操作,且持有Collection实例。

5、责任链模式(Chain of Responsibility)

有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。但是发出者并不清楚到底最终哪个对象会处理该请求,所以,责任链模式可以实现,在隐瞒客户端的情况下,对系统进行动态的调整。

链接上的请求可以是一条链,可以是一个树,还可以是一个环,模式本身不约束这个,需要我们自己去实现,同时,在一个时刻,命令只允许由一个对象传给另一个对象,而不允许传给多个对象。

接口

public interface Handler { 
    
    public void operator();
    
}

抽象类

public abstract class AbstractHandler {  
    
    private Handler handler;  
  
    public Handler getHandler() {  
        return handler;  
    }  
  
    public void setHandler(Handler handler) {  
        this.handler = handler;  
    }  
      
}

继承、实现类

public class MyHandler extends AbstractHandler implements Handler {  
      
    private String name;  
  
    public MyHandler(String name) {  
        this.name = name;  
    }  
  
    @Override  
    public void operator() {  
        System.out.println(name+"deal!");  
        if(getHandler()!=null){  
            getHandler().operator();  
        }  
    }
    
}  

测试类

public class Test {  
      
    public static void main(String[] args) {  
        MyHandler h1 = new MyHandler("h1");  
        MyHandler h2 = new MyHandler("h2");  
        MyHandler h3 = new MyHandler("h3");  
  
        h1.setHandler(h2);  
        h2.setHandler(h3);  
  
        h1.operator();  
    }
    
}  

6、命令模式(Command)

命令模式很好理解,举个例子,司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行。这个过程好在,三者相互解耦,任何一方都不用去依赖其他人,只需要做好自己的事儿就行,司令员要的是结果,不会去关注到底士兵是怎么实现的。

命令模式又称事务(Transaction)模式,命令模式用于封装向某个对象的请求。所谓请求,就是应用程序的操作人员通过图形用户界面(GUI)构件如按钮、图标、菜单项等发出的操作命令。命令模式通过在请求调用对象和请求的执行对象之间增加一个Command中间对象,用以消解多对多复杂性。

Invoker是调用者(司令员),Receiver是被调用者(士兵),MyCommand是命令,实现了Command接口,持有接收对象,看实现代码:

public interface Command {
    
    public void exe();
    
}
public class MyCommand implements Command {  
      
    private Receiver receiver;  
      
    public MyCommand(Receiver receiver) {  
        this.receiver = receiver;  
    }  
  
    @Override  
    public void exe() {  
        receiver.action();  
    }
    
}  
public class Receiver { 
    
    public void action(){  
        System.out.println("command received!");  
    }  
    
}
public class Invoker {  
    
    private Command command;  
      
    public Invoker(Command command) {  
        this.command = command;  
    }  
  
    public void action(){  
        command.exe();  
    } 
    
} 

测试类

public class Test {  
      
    public static void main(String[] args) {  
        Receiver receiver = new Receiver();  
        Command cmmand = new MyCommand(receiver);  
        Invoker invoker = new Invoker(cmmand);  
        invoker.action();  
    } 
    
} 

7、备忘录模式(Memento)

主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象,个人觉得叫备份模式更形象些,通俗的讲下:假设有原始类A,A中有各种属性,A可以决定需要备份的属性,备忘录类B是用来存储A的一些内部状态,类C呢,就是一个用来存储备忘录的,且只能存储,不能修改等操作

原始类

public class Original {  
    
    private String value;  
      
    public String getValue() {  
        return value;  
    }  
  
    public void setValue(String value) {  
        this.value = value;  
    }  
  
    public Original(String value) {  
        this.value = value;  
    }  
  
    //创建备忘录
    public Memento createMemento(){  
        return new Memento(value);  
    }  
    
    //获取备忘录内容
    public void restoreMemento(Memento memento){  
        this.value = memento.getValue();  
    }
    
}  

备忘录类

public class Memento {  
    
    private String value;  
  
    public Memento(String value) {  
        this.value = value;  
    }  
  
    public String getValue() {  
        return value;  
    }  
  
    public void setValue(String value) {  
        this.value = value;  
    }  
    
} 

仓库类

public class Storage {  
    
    private Memento memento;  
      
    public Storage(Memento memento) {  
        this.memento = memento;  
    }  
  
    public Memento getMemento() {  
        return memento;  
    }  
  
    public void setMemento(Memento memento) {  
        this.memento = memento;  
    } 
    
}  

测试类

public class Test {  
      
    public static void main(String[] args) {  
        // 创建原始类  
        Original origi = new Original("wang");  
  
        // 创建并保存备忘录  
        Storage storage = new Storage(origi.createMemento());  
  
        // 修改原始类的状态  
        System.out.println("初始化状态为:" + origi.getValue());  
        origi.setValue("bo");  
        System.out.println("修改后的状态为:" + origi.getValue());  
  
        // 恢复原始类的状态  
        origi.restoreMemento(storage.getMemento());  
        System.out.println("恢复后的状态为:" + origi.getValue());  
    }
    
}  

Original类是原始类,里面有需要保存的属性value及创建一个备忘录类,用来保存value值。Memento类是备忘录类,Storage类是存储备忘录的类,持有Memento类的实例。

新建原始类时,value被初始化为wang,后经过修改,将value的值置为bo,最后倒数第二行进行恢复状态,结果成功恢复了。其实我觉得这个模式叫“备份-恢复”模式最形象。

8、状态模式(State)

核心思想就是:当对象的状态改变时,同时改变其行为,很好理解!就拿QQ来说,有几种状态,在线、隐身、忙碌等,每个状态对应不同的操作,而且你的好友也能看到你的状态,所以,状态模式就两点:1、可以通过改变状态来获得不同的行为。2、你的好友能同时看到你的变化。

State类是个状态类,Context类可以实现切换,我们来看看代码:

状态类

public class State {  
    
    private String value;  
      
    public String getValue() {  
        return value;  
    }  
  
    public void setValue(String value) {  
        this.value = value;  
    }  
  
    public void method1(){  
        System.out.println("execute the first opt!");  
    }  
      
    public void method2(){  
        System.out.println("execute the second opt!");  
    }
    
}  

切换类

public class Context {  
      
    private State state;  
  
    public Context(State state) {  
        this.state = state;  
    }  
  
    public State getState() {  
        return state;  
    }  
  
    public void setState(State state) {  
        this.state = state;  
    }  
  
    public void method() {  
        if (state.getValue().equals("state1")) {  
            state.method1();  
        } else if (state.getValue().equals("state2")) {  
            state.method2();  
        }  
    } 
    
}  

测试类

public class Test {  
      
    public static void main(String[] args) {  
          
        State state = new State();  
        Context context = new Context(state);  
          
        //设置第一种状态  
        state.setValue("state1");  
        context.method();  
          
        //设置第二种状态  
        state.setValue("state2");  
        context.method();  
    }  
    
}  

根据这个特性,状态模式在日常开发中用的挺多的,尤其是做网站的时候,我们有时希望根据对象的某一属性,区别开他们的一些功能,比如说简单的权限控制等。

9、访问者模式(Visitor)

访问者模式就是一种分离对象数据结构与行为的方法,通过这种分离,可达到为一个被访问者动态添加新的操作而无需做其它的修改的效果。

访问者类

public interface Visitor { 
    
    public void visit(Subject sub);
    
} 
public class MyVisitor implements Visitor {  
      
    @Override  
    public void visit(Subject sub) {  
        System.out.println("visit the subject:"+sub.getSubject());  
    }
    
}

主题类

public interface Subject {
    
    public void accept(Visitor visitor); 
    
    public String getSubject();
    
} 
public class MySubject implements Subject {  
      
    @Override  
    public void accept(Visitor visitor) {  
        visitor.visit(this);  
    }  
  
    @Override  
    public String getSubject() {  
        return "love";  
    }
    
}  

测试类

public class Test {  
      
    public static void main(String[] args) {  
        Visitor visitor = new MyVisitor();  
        Subject sub = new MySubject();  
        sub.accept(visitor);  
    }
    
} 

该模式适用场景:如果我们想为一个现有的类增加新功能,不得不考虑几个事情:

1、新功能会不会与现有功能出现兼容性问题?

2、以后会不会再需要添加?

3、如果类不允许修改代码怎么办?

面对这些问题,最好的解决方法就是使用访问者模式,访问者模式适用于数据结构相对稳定的系统,把数据结构和算法解耦。

10、中介者模式(Mediator)

中介者模式也是用来降低类类之间的耦合的,因为如果类类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改一个对象,其它关联的对象都得进行修改。如果使用中介者模式,只需关心和中介类的关系,具体类类之间的关系及调度交给中介就行,这有点像spring容器的作用。

User类统一接口,User1和User2分别是不同的对象,二者之间有关联,如果不采用中介者模式,则需要二者相互持有引用,这样二者的耦合度很高,为了解耦,引入了Mediator类,提供统一接口,MyMediator为其实现类,里面持有User1和User2的实例,用来实现对User1和User2的控制。这样User1和User2两个对象相互独立,他们只需要保持好和Mediator之间的关系就行,剩下的全由MyMediator类来维护!

中介接口

public interface Mediator {
    
    public void createMediator(); 
    
    public void workAll();  
    
} 

中介类

public class MyMediator implements Mediator {  
      
    private User user1; 
    
    private User user2;  
      
    public User getUser1() {  
        return user1;  
    }  
  
    public User getUser2() {  
        return user2;  
    }  
  
    @Override  
    public void createMediator() {  
        user1 = new User1(this);  
        user2 = new User2(this);  
    }  
  
    @Override  
    public void workAll() {  
        user1.work();  
        user2.work();  
    }  
    
}  

user对象类

public abstract class User {  
    
    private Mediator mediator;  
      
    public Mediator getMediator(){  
        return mediator;  
    }  
      
    public User(Mediator mediator) {  
        this.mediator = mediator;  
    }  
  
    public abstract void work();
    
}
public class User1 extends User {  
      
    public User1(Mediator mediator){  
        super(mediator);  
    }  
      
    @Override  
    public void work() {  
        System.out.println("user1 exe!");  
    } 
    
}
public class User2 extends User {  
      
    public User2(Mediator mediator){  
        super(mediator);  
    }  
      
    @Override  
    public void work() {  
        System.out.println("user2 exe!");  
    } 
    
}

测试类

public class Test {  
      
    public static void main(String[] args) {  
        Mediator mediator = new MyMediator();  
        mediator.createMediator();  
        mediator.workAll();  
    }  
    
} 

11、解释器模式(Interpreter)

一般主要应用在OOP开发中的编译器的开发中,所以适用面比较窄。

Context类是一个上下文环境类,Plus和Minus分别是用来计算的实现,代码如下:

public interface Expression {
    
    public int interpret(Context context); 
    
}  
public class Plus implements Expression {  
      
    @Override  
    public int interpret(Context context) {  
        return context.getNum1()+context.getNum2();  
    }  
    
}  
public class Minus implements Expression {  
      
    @Override  
    public int interpret(Context context) {  
        return context.getNum1()-context.getNum2();  
    }  
    
}  
public class Context {  
    
    private int num1;
    
    private int num2;  
      
    public Context(int num1, int num2) {  
        this.num1 = num1;  
        this.num2 = num2;  
    }  
      
    public int getNum1() {  
        return num1;  
    }  
    public void setNum1(int num1) {  
        this.num1 = num1;  
    }  
    public int getNum2() {  
        return num2;  
    }  
    public void setNum2(int num2) {  
        this.num2 = num2;  
    }  
      
}  

测试类

public class Test {  
      
    public static void main(String[] args) {  
        // 计算9+2-8的值  
        int result = new Minus().interpret(
                (new Context(new Plus().interpret(new Context(9, 2))
                        , 8)));  
        System.out.println(result);  
    } 
    
}  

原文链接:http://blog.csdn.net/zhangerqing/article/details/8194653

posted @ 2017-05-10 17:00  一线大码  Views(295)  Comments(0Edit  收藏  举报