zoukankan      html  css  js  c++  java
  • PatternsInJava文摘

    1. Factory

    定义:提供创建对象的接口.

    为何使用?我们需要将创建实例的责任与使用实例的责任分开

    public class Factory{
    public static Sample creator(){
    ....
    if (which==1)
    return new MySample();
    else if (which==2)
    return new HisSample();
    }
    }

    如何使用?
    工厂模式中有: 工厂方法(Factory Method) 抽象工厂(Abstract Factory).

    这两个模式没有很明显的区别,区别在于需要创建对象的复杂程度上。如果我们创建对象的方法变得复杂了,我们就可能要将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现

    public abstract class Factory{
    public abstract Sample creator();
    public abstract Sample2 creator();
    }
    public class SimpleFactory extends Factory{
    public Sample creator(){
    ......
    }
    public Sample2 creator(){
    ......
    }
    }
    public class BombFactory extends Factory{
    public Sample creator(){
    ......
    }
    public Sample2 creator(){
    ......
    }
    }

    上例中我们只有一类产品接口 Sample , 工厂方法和抽象工厂可以创建多个产品接口的实例,比如Sample2 Sample3
    FactoryMethod 往往只是创建单个的实例。Abstract Factory 创建一系列的实例组,这些实例彼此相关。

    2. Prototype

    定义:
    用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.

    如何使用?
    因为Java 中的提供clone()方法来实现对象的克隆(具体了解clone()按这里),所以
    Prototype 模式实现一下子变得很简单.

    public abstract class AbstractSpoon implements Cloneable
    {
    String spoonName;
    public void setSpoonName(String spoonName) {this.spoonName = spoonName;}
    public String getSpoonName() {return this.spoonName;}
    public Object clone()
    {
    Object object = null;
    try {
    object = super.clone();
    } catch (CloneNotSupportedException exception) {
    System.err.println("AbstractSpoon is not Cloneable");
    }
    return object;
    }
    }
    public class SaladSpoon extends AbstractSpoon
    {
    public SaladSpoon()
    {
    setSpoonName("Salad Spoon");
    }
    }
    public class SoupSpoon extends AbstractSpoon
    {
    public SoupSpoon()
    {
    setSpoonName("Soup Spoon");
    }
    }

    AbstractSpoon spoon1 = new SoupSpoon();
    AbstractSpoon spoon2 = spoon1.clone();

    3. Builder

    Builder 模式定义:
    将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.

    为何使用?
    是为了将构建复杂对象的过程和它的部件解耦.注意: 是解耦过程和部件.

    如何使用?

    public interface Builder {
    //创建部件A 比如创建汽车车轮
    void buildPartA();
    //创建部件B 比如创建汽车方向盘
    void buildPartB();
    //创建部件C 比如创建汽车发动机
    void buildPartC();
    //返回最后组装成品结果 (返回最后装配好的汽车)
    //成品的组装过程不在这里进行,而是转移到下面的Director 类中
    进行.
    //从而实现了解耦过程和部件
    Product getResult();
    }
    public class ConcreteBuilder implements Builder {
    Part partA, partB, partC;
    public void buildPartA() {
    //这里是具体如何构建partA 的代码
    };
    public void buildPartB() {
    //这里是具体如何构建partB 的代码
    };
    public void buildPartC() {
    //这里是具体如何构建partB 的代码
    };
    public 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();
    }
    }

    复杂对象:产品Product:
    public interface Product { }
    复杂对象的部件:
    public interface Part { }

    我们看看如何调用Builder 模式:
    ConcreteBuilder builder = new ConcreteBuilder();
    Director director = new Director( builder );
    director.construct();
    Product product = builder.getResult();

    4. Singleton

    定义:
    Singleton 模式主要作用是保证在Java 应用程序中,一个Class 只有一个实例存在。

    如何使用?

    public class Singleton {
    private static Singleton _instance = new Singleton();
    public static Singleton getInstance() {
    return _instance;
    }
    }
    调用方法:
    Singleton.getInstance()
    public class Singleton {
    private static Singleton _instance = null;
    public static Singleton getInstance() {
    if (_instance==null)
    _instancenew Singleton()
    return _instance;
    }
    }
    调用方法:
    Singleton.getInstance()

    5. Facade

    Facade 的定义: 为子系统中的一组接口提供一个一致的界面.

    Facade 一个典型应用就是数据库JDBC 的应用,如下例对数据库的操作:

    public class DBCompare {
    Connection conn = null;
    PreparedStatement prep = null;
    ResultSet rset = null;
    try {
    Class.forName( "<driver>" ).newInstance();
    conn = DriverManager.getConnection( "<database>" );
    String sql = "SELECT * FROM <table> WHERE <column name> = ?";
    prep = conn.prepareStatement( sql );
    prep.setString( 1, "<column value>" );
    rset = prep.executeQuery();
    if( rset.next() ) {
    System.out.println( rset.getString( "<column name" ) );
    }
    } catch( SException e ) {
    e.printStackTrace();
    } finally {
    rset.close();
    prep.close();
    conn.close();
    }
    }

    上例是Jsp 中最通常的对数据库操作办法.
    在应用中,经常需要对数据库操作,每次都写上述一段代码肯定比较麻烦,需要将其中不变的
    部分提炼出来,做成一个接口,这就引入了facade 外观对象.如果以后我们更换
    Class.forName 中的<driver>也非常方便,比如从Mysql 数据库换到Oracle 数据库,只要更
    换facade 接口中的driver 就可以.

    6.Proxy

    Proxy 是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结
    构,Proxy 是代理的意思,我们也许有代理服务器等概念,代理概念可以解释为:在出发点到
    目的地之间有一道中间层,意为代理.
    设计模式中定义: 为其他对象提供一种代理以控制对这个对象的访问.

    为什么要使用Proxy?
    1.授权机制 不同级别的用户对同一对象拥有不同的访问权利,如Jive 论坛系统中,就使用
    Proxy 进行授权机制控制,访问论坛有两种人:注册用户和游客(未注册用户),Jive 中就通过
    类似ForumProxy 这样的代理来控制这两种用户对论坛的访问权限.
    2.某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.
    举例两个具体情况:
    (1)如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包
    含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待大图片处
    理完成,这时需要做个图片Proxy 来代替真正的图片.
    (2)如果那个对象在Internet 的某个远端服务器上,直接操作这个对象因为网络速度原因可
    能比较慢,那我们可以先用Proxy 来代替那个对象.
    总之原则是,对于开销很大的对象,只有在使用它时才创建,这个原则可以为我们节省很多宝
    贵的Java 内存. 所以,有些人认为Java 耗费资源内存,我以为这和程序编制思路也有一定的
    关系.

    public class ForumProxy implements Forum {
    private ForumPermissions permissions;
    private Forum forum;
    this.authorization = authorization;
    public ForumProxy(Forum forum, Authorization authorization,
    ForumPermissions permissions)
    {
    this.forum = forum;
    this.authorization = authorization;
    this.permissions = permissions;
    }
    .....
    public void setName(String name) throws UnauthorizedException,
    ForumAlreadyExistsException
    {
    //只有是系统或论坛管理者才可以修改名称
    if (permissions.isSystemOrForumAdmin()) {
    forum.setName(name);
    }
    else {
    throw new UnauthorizedException();
    }
    }

    而DbForum 才是接口Forum 的真正实现,以修改论坛名称为例:

    public class DbForum implements Forum, Cacheable {
    ...
    public void setName(String name) throws
    ForumAlreadyExistsException {
    ....
    this.name = name;
    //这里真正将新名称保存到数据库中
    saveToDb();
    ....
    }
    ...
    }

    7.Adapter

    定义:
    将两个不兼容的类纠合在一起使用,属于结构型模式,需要有Adaptee(被适配者)和
    Adaptor(适配器)两个身份.

    为何使用?
    我们经常碰到要将两个没有关系的类组合在一起使用,第一解决方案是:修改各自类的接口,
    但是如果我们没有源代码,或者,我们不愿意为了一个应用而修改各自的接口。 怎么办?
    使用Adapter,在这两种接口之间创建一个混合接口(混血儿).

    如何使用?
    实现Adapter 方式,其实"think in Java"的"类再生"一节中已经提到,有两种方式:组合
    (composition)和继承(inheritance).
    假设我们要打桩,有两种类:方形桩 圆形桩.

    public class SquarePeg{
    public void insert(String str){
    System.out.println("SquarePeg insert():"+str);
    }
    }
    public class RoundPeg{
    public void insertIntohole(String msg){
    System.out.println("RoundPeg insertIntoHole():"+msg);
    }
    }
    public class PegAdapter extends SquarePeg{
    private RoundPeg roundPeg;
    public PegAdapter(RoundPeg peg)(this.roundPeg=peg;)
    public void insert(String str){ roundPeg.insertIntoHole(str);}
    }

    8.Composite

    Composite 定义:
    将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和
    组合对象的使用具有一致性.

    Composite 比较容易理解,想到Composite 就应该想到树形结构图。组合体内这些对象都有
    共同接口,当组合体一个对象的方法被调用执行时,Composite 将遍历(Iterator)整个树形
    结构,寻找同样包含这个方法的对象并实现调用执行。可以用牵一动百来形容。
    所以Composite 模式使用到Iterator 模式,和Chain of Responsibility 模式类似。
    Composite 好处:
    1.使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关系自
    己处理的是单个对象还是整个组合结构,这就简化了客户端代码。
    2.更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。

    public abstract class Equipment
    {
    private String name;
    //网络价格
    public abstract double netPrice();
    //折扣价格
    public abstract double discountPrice();
    //增加部件方法
    public boolean add(Equipment equipment) { return false; }
    //删除部件方法
    public boolean remove(Equipment equipment) { return false; }
    //注意这里,这里就提供一种用于访问组合体类的部件方法。
    public Iterator iter() { return null; }
    public Equipment(final String name) { this.name=name; }
    }
    public class Disk extends Equipment
    {
    public Disk(String name) { super(name); }
    //定义Disk 网络价格为1
    public double netPrice() { return 1.; }
    //定义了disk 折扣价格是0.5 对折。
    public double discountPrice() { return .5; }
    }
    abstract class CompositeEquipment extends Equipment
    {
    private int i=0;
    //定义一个Vector 用来存放'儿子'
    private Lsit equipment=new ArrayList();
    public CompositeEquipment(String name) { super(name); }
    public boolean add(Equipment equipment) {
    this.equipment.add(equipment);
    return true;
    }
    public double netPrice()
    {
    double netPrice=0.;
    Iterator iter=equipment.iterator();
    for(iter.hasNext())
    netPrice+=((Equipment)iter.next()).netPrice();
    return netPrice;
    }
    public double discountPrice()
    {
    double discountPrice=0.;
    Iterator iter=equipment.iterator();
    for(iter.hasNext())
    设计模式(Patterns in Java) -- http://www.jdon.com
    35
    discountPrice+=((Equipment)iter.next()).discountPrice();
    return discountPrice;
    }
    //注意这里,这里就提供用于访问自己组合体内的部件方法。
    //上面dIsk 之所以没有,是因为Disk 是个单独(Primitive)的元素.
    public Iterator iter()
    {
    return equipment.iterator() ;
    {
    //重载Iterator 方法
    public boolean hasNext() { return i<equipment.size(); }
    //重载Iterator 方法
    public Object next()
    {
    if(hasNext())
    return equipment.elementAt(i++);
    else
    throw new NoSuchElementException();
    }
    }
    public class Chassis extends CompositeEquipment
    {
    public Chassis(String name) { super(name); }
    public double netPrice() { return 1.+super.netPrice(); }
    public double discountPrice()
    { return .5+super.discountPrice(); }
    }
    public class Cabinet extends CompositeEquipment
    {
    设计模式(Patterns in Java) -- http://www.jdon.com
    36
    public Cabinet(String name) { super(name); }
    public double netPrice() { return 1.+super.netPrice(); }
    public double discountPrice()
    { return .5+super.discountPrice(); }
    }

    至此我们完成了整个Composite 模式的架构。
    我们可以看看客户端调用Composote 代码:
    Cabinet cabinet=new Cabinet("Tower");
    Chassis chassis=new Chassis("PC Chassis");
    //将PC Chassis 装到Tower 中 (将盘盒装到箱子里)
    cabinet.add(chassis);
    //将一个10GB 的硬盘装到 PC Chassis (将硬盘装到盘盒里)
    chassis.add(new Disk("10 GB"));
    //调用 netPrice()方法;
    System.out.println("netPrice="+cabinet.netPrice());
    System.out.println("discountPrice="+cabinet.discountPrice());
    上面调用的方法netPrice()或discountPrice(),实际上Composite 使用Iterator 遍历了
    整个树形结构,寻找同样包含这个方法的对象并实现调用执行.
    Composite 是个很巧妙体现智慧的模式,在实际应用中,如果碰到树形结构,我们就可以尝
    试是否可以使用这个模式。

    9.Decorator

    Decorator 定义:
    动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator 模式相比用生成
    子类方式达到功能的扩充显得更为灵活.

    为什么使用Decorator?
    我们通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势
    必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓
    展功能,这些功能是编译时就确定了,是静态的.
    使用Decorator 的理由是:这些功能需要由用户动态决定加入的方式和时机.Decorator 提供
    了"即插即用"的方法,在运行期间决定何时增加何种功能.

    public interface Work
    {
    public void insert();
    }
    
    public class SquarePeg implements Work{
    public void insert(){
    System.out.println("方形桩插入");
    }
    }
    
    public class Decorator implements Work{
    private Work work;
    //额外增加的功能被打包在这个List 中
    private ArrayList others = new ArrayList();
    //在构造器中使用组合new 方式,引入Work 对象;
    public Decorator(Work work)
    {
    this.work=work;
    others.add("挖坑");
    others.add("钉木板");
    }
    public void insert(){
    newMethod();
    }
    //在新方法中,我们在insert 之前增加其他方法,这里次序先后是用
    户灵活指定的
    public void newMethod()
    {
    otherMethod();
    work.insert();
    }
    public void otherMethod()
    {
    ListIterator listIterator = others.listIterator();
    while (listIterator.hasNext())
    {
    System.out.println(((String)(listIterator.next()))
    + " 正在进行");
    }
    }
    }

    好了,Decorator 模式出来了,我们看如何调用:
    Work squarePeg = new SquarePeg();
    Work decorator = new Decorator(squarePeg);
    decorator.insert();
    Decorator 模式至此完成.
    如果你细心,会发现,上面调用类似我们读取文件时的调用:
    FileReader fr = new FileReader(filename);
    BufferedReader br = new BufferedReader(fr);
    实际上Java 的I/O API 就是使用Decorator 实现的,I/O 变种很多,如果都采取继承方法,
    将会产生很多子类,显然相当繁琐

    10.Bridge

    Bridge 定义 :
    将抽象和行为划分开来,各自独立,但能动态的结合.

    为什么使用?
    通常,当一个抽象类或接口有多个具体实现(concrete subclass),这些concrete 之间关系可
    能有以下两种:
    1. 这多个具体实现之间恰好是并列的,如前面举例,打桩,有两个concrete class:方形桩和
    圆形桩;这两个形状上的桩是并列的,没有概念上的重复,那么我们只要使用继承就可以了.
    2.实际应用上,常常有可能在这多个concrete class 之间有概念上重叠.那么需要我们把抽
    象共同部分和行为共同部分各自独立开来,原来是准备放在一个接口里,现在需要设计两个
    接口,分别放置抽象和行为.
    例如,一杯咖啡为例,有中杯和大杯之分,同时还有加奶 不加奶之分. 如果用单纯的继承,这
    四个具体实现(中杯 大杯 加奶 不加奶)之间有概念重叠,因为有中杯加奶,也有中杯不加奶,
    如果再在中杯这一层再实现两个继承,很显然混乱,扩展性极差.那我们使用Bridge 模式来
    实现它.
    如何实现?
    以上面提到的咖啡 为例. 我们原来打算只设计一个接口(抽象类),使用Bridge 模式后,我
    们需要将抽象和行为分开,加奶和不加奶属于行为,我们将它们抽象成一个专门的行为接口.

    public abstract class Coffee
    {
    CoffeeImp coffeeImp;
    public void setCoffeeImp() {
    this.CoffeeImp = CoffeeImpSingleton.getTheCoffeImp();
    }
    public CoffeeImp getCoffeeImp() {return this.CoffeeImp;}
    public abstract void pourCoffee();
    }
    public abstract class CoffeeImp
    {
    public abstract void pourCoffeeImp();
    }
    //中杯
    public class MediumCoffee extends Coffee
    {
    public MediumCoffee() {setCoffeeImp();}
    public void pourCoffee()
    {
    CoffeeImp coffeeImp = this.getCoffeeImp();
    //我们以重复次数来说明是冲中杯还是大杯 ,重复2 次是中杯
    for (int i = 0; i < 2; i++)
    {
    coffeeImp.pourCoffeeImp();
    }
    }
    }
    //大杯
    public class SuperSizeCoffee extends Coffee
    {
    public SuperSizeCoffee() {setCoffeeImp();}
    public void pourCoffee()
    {
    CoffeeImp coffeeImp = this.getCoffeeImp();
    //我们以重复次数来说明是冲中杯还是大杯 ,重复5 次是大杯
    for (int i = 0; i < 5; i++)
    {
    coffeeImp.pourCoffeeImp();
    }
    }
    }
    //加奶
    public class MilkCoffeeImp extends CoffeeImp
    {
    MilkCoffeeImp() {}
    public void pourCoffeeImp()
    {
    System.out.println("加了美味的牛奶");
    }
    }
    //不加奶
    public class FragrantCoffeeImp extends CoffeeImp
    {
    FragrantCoffeeImp() {}
    public void pourCoffeeImp()
    {
    System.out.println("什么也没加,清香");
    }
    }
    public class CoffeeImpSingleton
    {
    private static CoffeeImp coffeeImp;
    public CoffeeImpSingleton(CoffeeImp coffeeImpIn)
    {this.coffeeImp = coffeeImpIn;}
    public static CoffeeImp getTheCoffeeImp()
    {
    return coffeeImp;
    }
    }

    看看中杯加奶 和大杯加奶 是怎么出来的:
    //拿出牛奶
    CoffeeImpSingleton coffeeImpSingleton = new CoffeeImpSingleton(new
    MilkCoffeeImp());
    //中杯加奶
    MediumCoffee mediumCoffee = new MediumCoffee();
    mediumCoffee.pourCoffee();
    //大杯加奶
    SuperSizeCoffee superSizeCoffee = new SuperSizeCoffee();
    superSizeCoffee.pourCoffee();
    注意: Bridge 模式的执行类如CoffeeImp 和Coffee 是一对一的关系, 正确创建CoffeeImp
    是该模式的关键,

    11.Flyweight

    Flyweight 定义:
    避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类).

    为什么使用?
    面向对象语言的原则就是一切都是对象,但是如果真正使用起来,有时对象数可能显得很庞
    大,比如,字处理软件,如果以每个文字都作为一个对象,几千个字,对象数就是几千,无疑耗
    费内存,那么我们还是要"求同存异",找出这些对象群的共同点,设计一个元类,封装可以被
    共享的类,另外,还有一些特性是取决于应用(context),是不可共享的,这也Flyweight 中两
    个重要概念内部状态intrinsic 和外部状态extrinsic 之分.
    说白点,就是先捏一个的原始模型,然后随着不同场合和环境,再产生各具特征的具体模型,
    很显然,在这里需要产生不同的新对象,所以Flyweight 模式中常出现Factory 模
    式.Flyweight 的内部状态是用来共享的,Flyweight factory 负责维护一个Flyweight
    pool(模式池)来存放内部状态的对象.
    Flyweight 模式是一个提高程序效率和性能的模式,会大大加快程序的运行速度.应用场合
    很多:比如你要从一个数据库中读取一系列字符串,这些字符串中有许多是重复的,那么我们
    可以将这些字符串储存在Flyweight 池(pool)中.

    public interface Flyweight
    {
    public void operation( ExtrinsicState state );
    }
    //用于本模式的抽象数据类型(自行设计)
    public interface ExtrinsicState { }
    public class ConcreteFlyweight implements Flyweight {
    private IntrinsicState state;
    public void operation( ExtrinsicState state )
    {
    //具体操作
    }
    }
    public class UnsharedConcreteFlyweight implements Flyweight {
    public void operation( ExtrinsicState state ) { }
    }

    Flyweight factory 负责维护一个Flyweight 池(存放内部状态),当客户端请求一个共享
    Flyweight 时,这个factory 首先搜索池中是否已经有可适用的,如果有,factory 只是简单返
    回送出这个对象,否则,创建一个新的对象,加入到池中,再返回送出这个对象.池

    public class FlyweightFactory {
    //Flyweight pool
    private Hashtable flyweights = new Hashtable();
    public Flyweight getFlyweight( Object key ) {
    Flyweight flyweight = (Flyweight) flyweights.get(key);
    if( flyweight == null ) {
    //产生新的ConcreteFlyweight
    flyweight = new ConcreteFlyweight();
    flyweights.put( key, flyweight );
    }
    return flyweight;
    }
    }

    至此,Flyweight 模式的基本框架已经就绪,我们看看如何调用:
    FlyweightFactory factory = new FlyweightFactory();
    Flyweight fly1 = factory.getFlyweight( "Fred" );
    Flyweight fly2 = factory.getFlyweight( "Wilma" );

    12.Template

    Template 定义:
    定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中.

    public abstract class Benchmark
    {
    /**
    * 下面操作是我们希望在子类中完成
    */
    public abstract void benchmark();
    /**
    * 重复执行benchmark 次数
    */
    public final long repeat (int count) {
    if (count <= 0)
    return 0;
    else {
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < count; i++)
    benchmark();
    long stopTime = System.currentTimeMillis();
    return stopTime - startTime;
    }
    }
    }
    public class MethodBenchmark extends Benchmark
    {
    /**
    * 真正定义benchmark 内容
    */
    public void benchmark() {
    for (int i = 0; i < Integer.MAX_VALUE; i++){
    System.out.printtln("i="+i);
    }
    }
    }

    Benchmark operation = new MethodBenchmark();
    long duration = operation.repeat(Integer.parseInt(args[0].trim()));
    System.out.println("The operation took " + duration + " milliseconds");

    13.Memento

    Memento 定义:
    memento 是一个保存另外一个对象内部状态拷贝的对象.这样以后就可以将该对象恢复到原
    先保存的状态.

    public class Originator {
    private int number;
    private File file = null;
    public Originator(){}
    // 创建一个Memento
    public Memento getMemento(){
    return new Memento(this);
    }
    // 恢复到原始值
    public void setMemento(Memento m){
    number = m.number;
    file = m.file;
    }
    }
    private class Memento implements java.io.Serializable{
    private int number;
    private File file = null;
    public Memento( Originator o){
    number = o.number;
    file = o.file;
    }
    }

    可见 Memento 中保存了Originator 中的number 和file 的值. 通过调用Originator 中
    number 和file 值改变的话,通过调用setMemento()方法可以恢复.
    Memento 模式的缺点是耗费大,如果内部状态很多,再保存一份,无意要浪费大量内存.

    14.Observer

    public class product extends Observable{
    private String name;
    private float price;
    public String getName(){ return name;}
    public void setName(){
    this.name=name;
    //设置变化点
    setChanged();
    notifyObservers(name);
    }
    public float getPrice(){ return price;}
    public void setPrice(){
    this.price=price;
    //设置变化点
    setChanged();
    notifyObservers(new Float(price));
    }
    //以下可以是数据库更新 插入命令.
    public void saveToDb(){
    .....................
    }
    //观察者NameObserver 主要用来对产品名称(name)进行观察的
    public class NameObserver implements Observer{
    private String name=null;
    public void update(Observable obj,Object arg){
    if (arg instanceof String){
    name=(String)arg;
    //产品名称改变值在name 中
    System.out.println("NameObserver :name changet to "+name);
    }
    }
    }
    //观察者PriceObserver 主要用来对产品价格(price)进行观察的
    public class PriceObserver implements Observer{
    private float price=0;
    public void update(Observable obj,Object arg){
    if (arg instanceof Float){
    price=((Float)arg).floatValue();
    System.out.println("PriceObserver :price changet to "+price);
    }
    }
    }

    Product product=new Product();
    NameObserver nameobs=new NameObserver();
    PriceObserver priceobs=new PriceObserver();
    //加入观察者
    product.addObserver(nameobs);
    product.addObserver(priceobs);
    product.setName("橘子红了");
    product.setPrice(9.22f);

    15.Chain of Responsibility

    Chain of Responsibility 定义
    Chain of Responsibility(CoR) 是用一系列类(classes)试图处理一个请求request,这些
    类之间是一个松散的耦合,唯一共同点是在他们之间传递request. 也就是说,来了一个请
    求,A 类先处理,如果没有处理,就传递到B 类处理,如果没有处理,就传递到C 类处理,
    就这样象一个链条(chain)一样传递下去。

    CoR 的优点:
    因为无法预知来自外界的请求是属于哪种类型,每个类如果碰到它不能处理的请求只要放弃
    就可以。无疑这降低了类之间的耦合性。
    缺点是效率低,因为一个请求的完成可能要遍历到最后才可能完成,当然也可以用树的概念
    优化。 在Java AWT1.0 中,对于鼠标按键事情的处理就是使用CoR,到Java.1.1 以后,就
    使用Observer 代替CoR
    扩展性差,因为在CoR 中,一定要有一个统一的接口Handler.局限性就在这里。

    16.Command

    Command 定义
    不少Command 模式的代码都是针对图形界面的,它实际就是菜单命令,我们在一个下拉菜单
    选择一个命令时,然后会执行一些动作.
    将这些命令封装成在一个类中,然后用户(调用者)再对这个类进行操作,这就是Command 模
    式,换句话说,本来用户(调用者)是直接调用这些命令的,如菜单上打开文档(调用者),就直
    接指向打开文档的代码,使用Command 模式,就是在这两者之间增加一个中间者,将这种直接
    关系拗断,同时两者之间都隔离,基本没有关系了.
    显然这样做的好处是符合封装的特性,降低耦合度,Command 是将对行为进行封装的典型模
    式,Factory 是将创建进行封装的模式,
    从Command 模式,我也发现设计模式一个"通病":好象喜欢将简单的问题复杂化, 喜欢在不
    同类中增加第三者,当然这样做有利于代码的健壮性 可维护性 还有复用性.

    如何使用?
    具体的Command 模式代码各式各样,因为如何封装命令,不同系统,有不同的做法.下面事例
    是将命令封装在一个Collection 的List 中,任何对象一旦加入List 中,实际上装入了一个
    封闭的黑盒中,对象的特性消失了,只有取出时,才有可能模糊的分辨出:
    典型的Command 模式需要有一个接口.接口中有一个统一的方法,这就是"将命令/请求封装
    为对象":

    public interface Command {
    public abstract void execute ( );
    }
    
    public class Engineer implements Command {
    public void execute( ) {
    //do Engineer's command
    }
    }
    public class Programmer implements Command {
    public void execute( ) {
    //do programmer's command
    }
    }
    public class Politician implements Command {
    public void execute( ) {
    //do Politician's command
    }
    }
    
    public class producer{
    public static List produceRequests() {
    List queue = new ArrayList();
    queue.add( new Engineer() );
    queue.add( new Politician() );
    queue.add( new Programmer() );
    return queue;
    }
    }
    public class TestCommand {
    public static void main(String[] args) {
    List queue = Producer.produceRequests();
    for (Iterator it = queue.iterator(); it.hasNext(); )
    //取出List 中东东,其他特征都不能确定,只能保证一
    个特征是100%正确,
    // 他们至少是接口Command 的"儿子".所以强制转换
    类型为接口Command
    ((Command)it.next()).execute();
    }
    }

    17.State/Strategy

    State 的定义: 不同的状态,不同的行为;或者说,每个状态有着相应的行为.

    何时使用?
    State 模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If elseif else
    进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取
    State 模式了.
    不只是根据状态,也有根据属性.如果某个对象的属性不同,对象的行为就不一样,这点在数
    据库系统中出现频率比较高,我们经常会在一个数据表的尾部,加上property 属性含义的字
    段,用以标识记录中一些特殊性质的记录,这种属性的改变(切换)又是随时可能发生的,就有
    可能要使用State.

    --------------------------------------------------

    Strategy 是属于设计模式中 对象行为型模式,主要是定义一系列的算法,把这些算法一个
    个封装成单独的类.

    18.Mediator

    Mediator 定义:
    用一个中介对象来封装一系列关于对象交互行为.

    为何使用Mediator?
    各个对象之间的交互操作非常多;每个对象的行为操作都依赖彼此对方,修改一个对象的行
    为,同时会涉及到修改很多其他对象的行为,如果使用Mediator 模式,可以使各个对象间的
    耦合松散,只需关心和 Mediator 的关系,使多对多的关系变成了一对多的关系,可以降低系
    统的复杂性,提高可修改扩展性.

    public interface Mediator { }

    public class ConcreteMediator implements Mediator {
    //假设当前有两个成员.
    private ConcreteColleague1 colleague1 = new ConcreteColleague1();
    private ConcreteColleague2 colleague2 = new ConcreteColleague2();
    ...
    }

    public class Colleague {
    private Mediator mediator;
    public Mediator getMediator() {
    return mediator;
    }
    public void setMediator( Mediator mediator ) {
    this.mediator = mediator;
    }
    }
    public class ConcreteColleague1 { }
    public class ConcreteColleague2 { }

    每个成员都必须知道Mediator,并且和 Mediator 联系,而不是和其他成员联系.
    至此,Mediator 模式框架完成,可以发现Mediator 模式规定不是很多,大体框架也比较简单,
    但实际使用起来就非常灵活.
    Mediator 模式在事件驱动类应用中比较多,例如界面设计GUI.;聊天,消息传递等,在聊天应
    用中,需要有一个MessageMediator,专门负责request/reponse 之间任务的调节.
    MVC 是J2EE 的一个基本模式,View Controller 是一种Mediator,它是Jsp 和服务器上应用
    程序间的Mediator.

    19.Interpreter

    Interpreter 定义:
    定义语言的文法 ,并且建立一个解释器来解释该语言中的句子.

    20.Visitor

    Visitor 定义
    作用于某个对象群中各个对象的操作. 它可以使你在不改变这些对象本身的情况下,定义作
    用于这些对象的新操作.

  • 相关阅读:
    CodeForces 1105D-暴力BFS
    POJ 1258 Agri-Net (最小生成树)
    POJ 1251 Jungle Roads (最小生成树)
    hiho 1097 最小生成树一·Prim算法 (最小生成树)
    Codeforces 544E K Balanced Teams (DP)
    Codeforces 408D Long Path (DP)
    PTA L1题目合集(更新至2019.3)
    HDOJ 3308 LCIS (线段树)
    HDOJ 1698 Just a Hook (线段树)
    HDOJ 4267 A Simple Problem with Integers (线段树)
  • 原文地址:https://www.cnblogs.com/smileberry/p/2651121.html
Copyright © 2011-2022 走看看