Java23种设计模式

1、设计模式入门:

1.设计模式是人们在面对同类型软件工程设计问题所总结出的一些有用经验。模式不是代码,而是某类问题的通用设计解决方案
2.设计模式的本质目的是使软件工程在维护性、扩展性、变化性、复杂度方面成O(N)
3.OOP是原则,设计模式是具体方法、工具
————————————————————————————————————————————
java

2、策略模式

从文字方面可能咱们很难理解,因此咱们从实际项目入手android

如今假设咱们有个“鸭子项目”,首先咱们用OOP的角度设计这个项目,找到鸭子中共同的特性抽取在父类中并具体实现,不一样的特性不实现,由子类具体实现,好下面看代码:程序员

public abstract class Duck {
    /** * 叫声和游泳为相同的特性抽取并具体实现 */
    public void Quack() {
        System.out.println("~~gaga~~");
    }
    public void swim() {
        System.out.println("~~im swim~~");
    }

    /** * 外貌为不一样的特性设计为抽象的方法,有子类具体实现 */
    public abstract void display();

}

如今咱们看它的子类:web

public class GreenHeadDuck extends Duck {
    @Override
    public void display() {
        System.out.println("**GreenHead**");
    }
}
public class RedHeadDuck extends Duck {
    @Override
    public void display() {
        System.out.println("**RedHead**");
    }
}

好的,如今咱们能够看到使用OOP能够很好的解决目前的问题,可是咱们每每是需求不断,因此咱们如今又来一个新需求:添加会飞的鸭子算法

好办啊,咱们只要在父类中添加一个新的方法:数据库

public abstract class Duck {
    /** * 叫声和游泳为相同的特性抽取并具体实现 */
    public void Quack() {
        System.out.println("~~gaga~~");
    }
    public void swim() {
        System.out.println("~~im swim~~");
    }

    /**针对新需求的方法*/
    public void Fly() {
        System.out.println("~~im fly~~");
    }

    /** * 外貌为不一样的特性设计为抽象的方法,有子类具体实现 */
    public abstract void display();

}

问题来了,这个Fly让全部子类都会飞了,这是不科学的。express

继承的问题:对类的局部改动,尤为超类的局部改动,会影响其余部分。影响会有溢出效应编程

好如今咱们继续用OOP的方式去解决,使其子类覆盖Fly:设计模式

public class GreenHeadDuck extends Duck {
    @Override
    public void display() {
        System.out.println("**GreenHead**");
    }

    /** * 覆盖 * */
    public void Fly() {
        System.out.println("~~no fly~~");
    }
}

能够看到貌似问题是解决了,咱们如今的鸭子类只有2种,若是有上百种呢,那不是都要去覆盖。因此这不是一种好的设计模式数组

分析问题:
须要新的设计方式,应对项目的扩展性,下降复杂度:
1)分析项目变化与不变部分,提取变化部分,抽象成接口+实现;
2)鸭子哪些功能是会根据新需求变化的?叫声、飞行…

咱们将变化的功能设计成接口,下面看代码:

public interface FlyBehavior {
    void fly();
}
public interface QuackBehavior {
    void quack();
}

来看看新的Duck类:

public abstract class Duck {
    /** * 父类定义行为出来,可是没有具体实例化 */
    FlyBehavior mFlyBehavior;
    QuackBehavior mQuackBehavior;

    public Duck() {
    }

    public void Fly() {
        if (mFlyBehavior!=null) {
            mFlyBehavior.fly();
        }
    }

    public void Quack() {
        if (mQuackBehavior!=null) {
            mQuackBehavior.quack();
        }
    }

    /** * 子类能够透过两个行为的set方法去动态改变本身的具体行为 */
    public void setmFlyBehavior(FlyBehavior mFlyBehavior) {
        this.mFlyBehavior = mFlyBehavior;
    }

    public void setmQuackBehavior(QuackBehavior mQuackBehavior) {
        this.mQuackBehavior = mQuackBehavior;
    }

    public abstract void display();
}

而后在去看看子类:

public class RedHeadDuck extends Duck{

    public RedHeadDuck() {
        mFlyBehavior=new GoodFlyBehavior();
        mQuackBehavior=new GaGaQuackBehavior();
    }
    @Override
    public void display() {
        System.out.println("redDuck");
    }
}
public class GreenHeadDuck extends Duck{

    public GreenHeadDuck() {
        mFlyBehavior=new BadFlyBehavior();
        mQuackBehavior=new GeGeQuackBehavior();
    }
    @Override
    public void display() {
        System.out.println("greenDuck");
    }

}

再来看看接口实现类:

public class BadFlyBehavior implements FlyBehavior{

    @Override
    public void fly() {
        System.out.println("bad fly");
    }

}
public class GoodFlyBehavior implements FlyBehavior{

    @Override
    public void fly() {
        System.out.println("good fly");
    }

}
public class NoFlyBehavior implements FlyBehavior{

    @Override
    public void fly() {
        System.out.println("No fly");
    }

}
public class GaGaQuackBehavior implements QuackBehavior{

    @Override
    public void quack() {
        System.out.println("gaga quack");
    }

}
public class GeGeQuackBehavior implements QuackBehavior{

    @Override
    public void quack() {
        System.out.println("gege quack");
    }

}
public class NoQuackBehavior implements QuackBehavior{

    @Override
    public void quack() {
        System.out.println("No Quack");
    }

}

好的,如今咱们来分析一下这个设计,在父类中咱们定义好FlyBehavior & QuackBehavior 两个行为接口,而后在子类构造方法中分别设定对应的具体行为

如今来测试一下:
这里写图片描述

策略模式:分别封装行为接口,实现算法族,超类里放行为接口对象,在子类里具体设定行为对象。原则就是:分离变化部分,封装接口,基于接口编程各类功能。此模式让行为算法的变化独立于算法的使用者

—————————————————————————————————————————————

3、观察者模式:

跟以前同样,咱们仍是经过实际项目入手,以后,这句话我就不重复了,直接从项目开始讲解了

如今假设咱们有一个须要为A公司实时提供天气的天气预报接口项目,好的,首先咱们仍是以OOP的方式去解决问题,首先咱们建立一个天气台对象并提供相关方法假设它能够实时为A公司提供天气数据,下面看代码:

public class MeteorologicalStation {
    private float pressure;
    private float temperature;
    private float humidity;
    private ACompany company;

    public MeteorologicalStation(ACompany company) {
        this.company=company;
    }

    public float getPressure() {
        return pressure;
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    /** * 实时提供天气状况 * */
    public void uploadData(float pressure,float temperature,float humidity){
        company.getMeteorologicalStationData(pressure, temperature, humidity);
    }

}

ACompany为A公司:

public class ACompany {
    public void getMeteorologicalStationData(float pressure, float temperature, float humidity) {
        System.out.println("pressure: "+pressure+",temperature: "+temperature+",humidity: "+humidity);
    }
}

测试
这里写图片描述

好的,到了这里咱们从OOP角度已经初步解决了这个项目,假设如今B公司也须要实时获取天气台提供的天气状况,若是咱们仍是继续使用OOP去设计这个项目,须要在天气台接口中添加BCompany,并在实时更新的函数中调用BCompany的获取天气的函数,这貌似能够解决这个需求,可是加入后续加入C,D,E..公司,那么天气台接口修改的代码也是比较大,可是咱们知道在一般实际开发中,接口通常不会随着他人的接入而更改,因此如今咱们使用观察者模式去设计这个项目:

/** * 该接口至关于天气台管理者,谁想接入我和离开我都必须经过它去管理 * */
public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifObserver();
}
/** * 经过该接口,每一个想要接入的公司实现该方法便可。 */
public interface Observer {
    void getMeteorologicalStationData(float pressure,float temperature,float humidity);
}
public class MeteorologicalStation implements Subject {
    private float pressure;
    private float temperature;
    private float humidity;
    private ArrayList<Observer> observers;

    public MeteorologicalStation(ACompany company) {
        observers = new ArrayList<Observer>();
    }

    public float getPressure() {
        return pressure;
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public void uploadData(float pressure, float temperature, float humidity) {
        this.pressure = pressure;
        this.temperature = temperature;
        this.humidity = humidity;
         notifObserver();
    }

    @Override
    public void registerObserver(Observer o) {
        if (!observers.contains(o)) {
            observers.add(o);
        }
    }

    @Override
    public void removeObserver(Observer o) {
        if (observers.contains(o)) {
            observers.remove(o);
        }
    }

    @Override
    public void notifObserver() {
        for (int i = 0; i < observers.size(); i++) {
            Observer observer = observers.get(i);
            observer.getMeteorologicalStationData(getPressure(), getTemperature(), getHumidity());
        }
    }

}

如今咱们来分析天气台类,天气台实现了Subject,并用集合的形式方便的管理多个客户的接入与离开,在notifObserver中实时的上传天气数据。好的,如今咱们看看其余客户的接入:

public class ACompany implements Observer{
    @Override
    public void getMeteorologicalStationData(float pressure,float temperature,float humidity){
        System.out.println("A pressure: "+pressure+",temperature: "+temperature+",humidity: "+humidity);
    }
}
public class BCompany implements Observer{

    @Override
    public void getMeteorologicalStationData(float pressure, float temperature, float humidity) {
        System.out.println("B pressure: "+pressure+",temperature: "+temperature+",humidity: "+humidity);
    }

}

好的咱们能够看到不管有多少个公司想要接入,如今只须要实现Observer接口便可。如今咱们来测试下:
这里写图片描述

看到这里咱们已经知道了观察者模式的好处,下面咱们看看java内置的观察者:

public class MeteorologicalStation extends Observable {
    private float pressure;
    private float temperature;
    private float humidity;

    public float getPressure() {
        return pressure;
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public void uploadData(float pressure, float temperature, float humidity) {
        this.pressure = pressure;
        this.temperature = temperature;
        this.humidity = humidity;
        WeatherData data=new WeatherData(pressure, temperature, humidity);
        /** * setChanged * 根据有些特定的需求出现的,设置后唤醒才有效, * 例如咱们不须要温度改变0.5咱们也去唤醒客户, * 所以这里咱们能够判断后在设置 * */
        this.setChanged();
        this.notifyObservers(data);
    }

     public class WeatherData{
         public float pressure;
         public float temperature;
         public float humidity;
         public WeatherData(float pressure, float temperature, float humidity) {
            this.pressure = pressure;
            this.temperature = temperature;
            this.humidity = humidity;
        }

    }
}

从代码中能够看到Observable 是一个类 而不是像咱们同样的Subject的接口,

this.setChanged();
this.notifyObservers(data);

两个一块儿使用才有效,下面咱们看看A,B公司须要怎么作:

public class ACompany implements Observer{

    @Override
    public void update(Observable arg0, Object arg1) {
        WeatherData data=(WeatherData) arg1;
        System.out.println("A pressure: "+data.pressure+",temperature: "+data.temperature+",humidity: "+data.humidity);
    }
}
public class BCompany implements Observer{

    @Override
    public void update(Observable o, Object arg) {
        WeatherData data=(WeatherData) arg;
        System.out.println("B pressure: "+data.pressure+",temperature: "+data.temperature+",humidity: "+data.humidity);
    }
}

A,B公司只要实现系统的Observer接口,和咱们刚才的设计是同样的。最后咱们在测试一下:
这里写图片描述
能够看到和咱们以前的效果彻底同样

—————————————————————————————————————————————

4、装饰者模式

咖啡馆订单系统项目:
咖啡种类:Espresso、ShortBlack、LongBlack、Decaf
调料:Milk、Soy、Chocolate
顾客首先选择咖啡种类,而后在选择是否须要调料,咱们须要描述出顾客选择的咖啡种类及其调料名称,及其花费的总价。

好的,如今咱们来看一个差的方案:
这里写图片描述
首先是定义了一个抽象的Drink父类,里面定义出一个抽象的cost()方法用于返回消费的总价,用setDescription去描述各个消费商品的名称,使用getDescrption将客户的消费订单打印,后面又将大概的客户消费可能出现的状况一一去列举出来,可是 因为这个消费状况太多,因此没有用代码去描述,各个消费状况继承Drink类,实现cost()抽象方法,使用父类的super.getPrice()返回总价,在构造中使用super.setDescriptin()和super.setPrice()分别去设置本身的产品名称及其价格。图中咱们能够看到加入有许多种状况,咱们须要定义太多的类。

好的,咱们在来看一个好一点的方案:
这里写图片描述
从图中能够看到基本和第一种方案基本相似,只是将调料的种类在父类中体现,若是顾客须要在咖啡中加入调料调用setXXX方法,使用hasXXX去判断是否有某中调料,可是就像图中所示,会产生若是增长调料种类,须要去更改父类的方法,而且此方式没法将同分调料增长多份

好的,咱们如今使用装饰者来看看:

public abstract class Drink {
    private int price;
    private String description;

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public String getDescription() {
        return description+"--"+this.getPrice();
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public abstract int cost();
}
public class Coffer extends Drink{

    @Override
    public int cost() {
        return super.getPrice();
    }
}
public class Decaf extends Coffer{
    public Decaf() {
        super.setDescription("脱因咖啡");
        super.setPrice(10);
    }
}
public class Espresso extends Coffer{

    public Espresso() {
        super.setDescription("浓咖啡");
        super.setPrice(11);
    }
}
public class LongBlack extends Coffer{

    public LongBlack() {
        super.setDescription("热咖啡");
        super.setPrice(12);
    }
}
public class ShortBlack extends Coffer{

    public ShortBlack() {
        super.setDescription("小杯黑咖啡");
        super.setPrice(13);
    }
}


从上面能够看出咱们首先定义出一个抽象的Drink父类,用于设置和获得各个咖啡的描述及其价格,而后定义出一个Coffer类继承自Drink类,重写cost()方法,用于返回每次消费的价格,各个咖啡类须要继承Coffer类在构造函中设置各自的描述及其价格,接下来咱们看看装饰者代码:

public class Decorator extends Drink{

    Drink drink;
    public Decorator(Drink drink) {
        this.drink=drink;
    }
    @Override
    public int cost() {
        return super.getPrice()+this.drink.cost();
    }
    @Override
    public String getDescription() {
        return super.getDescription()+"&&"+this.drink.getDescription();
    }

}

能够看到装饰者代码咱们须要继承自Drink类,构造函数中带入其做为参数,重写cost与getDescription方法,使用迭代的形式将每次添加的调料累加,造成一个循环,将其返回,:

public class Chocolate extends Decorator{

    public Chocolate(Drink drink) {
        super(drink);
        super.setDescription("巧克力");
        super.setPrice(2);
    }

}
public class Milk extends Decorator{

    public Milk(Drink drink) {
        super(drink);
        super.setDescription("牛奶");
        super.setPrice(2);
    }

}
public class Soy extends Decorator{

    public Soy(Drink drink) {
        super(drink);
        super.setDescription("大豆");
        super.setPrice(4);
    }

}

各个调料类须要继承自Decorator 装饰者类,而后在构造函数中带入Drink类做为参数,传给父类,并须要设置其价格及其描述,

好的如今咱们来测试下效果:

public class main {
    public static void main(String[] args) {
        LongBlack longBlack=new LongBlack();
        System.out.println("order1 price: "+longBlack.cost());
        System.out.println("order1 desc: "+longBlack.getDescription());

        System.out.println("---------------");
        Drink order;
        order=new Espresso();
        order=new Milk(order);
        order=new Chocolate(order);
        order=new Chocolate(order);
        System.out.println("order2 price: "+order.cost());
        System.out.println("order2 desc: "+order.getDescription());
    }
}

这里写图片描述

从上面的代码中咱们能够看出使用装饰者后,咱们不管须要多少调料都是能够累加的,加入有一天有一个新的咖啡种类或者调料,咱们只须要按照上面的相似就好了,无需去改动父类和增长许多类。

好的,如今咱们来看看java内置的装饰者模式:
这里写图片描述
从图中能够看出java 中IO流的设计就是咱们其中的装饰者模式,那好如今咱们也给本身添加一个大写额输入流类:

public class UpperCaseInputStream extends FilterInputStream{

    protected UpperCaseInputStream(InputStream in) {
        super(in);
    }

    @Override
    public int read() throws IOException {
        int c = super.read();
        return c==-1?c:Character.toUpperCase((char)(c));
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int size=super.read(b, off, len);
        for(int i=0;i<size;i++){
            b[i]=(byte) Character.toUpperCase((char)(size));
        }
        return size;
    }

}

从代码中能够看到很简单的继承FilterInputStream,而后在read方法中将其转换为大写便可,这种装饰者的设计使咱们能够很简单的去添加一个子类,咱们在来测试一下:

public class main {
    public static void main(String[] args) {
        InputStream is=null;
        int c=0;
        try {
            is=new FileInputStream("C:\\Users\\Administrator\\Desktop\\test.txt");
            is =new BufferedInputStream(is);
            is = new UpperCaseInputStream(is);
            while((c=is.read())>0){
                System.out.print((char)c);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

这里写图片描述
装饰着模式是一种开放-关闭原则的设计意义,开放即为之后设计添加子类方便,关闭即父类不用更改

—————————————————————————————————————————————

5、单例模式

巧克力工厂项目,工厂只有一个锅炉,往锅炉中添加佐料,若是满了则其余人不能再次添加,或者必须倾倒后添加,而后将锅炉烧开,若是锅炉已经烧开就无需再次烧开,或者必须倾倒后再次烧开

好的,首先咱们仍是用普通的方式去作:

public class ChocolateFactor {
    private boolean isEmpty;
    private boolean isBoiled;
    public ChocolateFactor() {
        isEmpty=true;
        isBoiled=false;
    }
    public void fill(){
        if (isEmpty) {
            isEmpty=false;
            isBoiled=false;
            System.out.println("锅炉满了");
        }
    }

    public void boil(){
        if ((!isEmpty)&&(!isBoiled)) {
            isBoiled=true;
            System.out.println("锅炉已经沸腾了");
        }
    }

    public void dump(){
        if ((!isEmpty)&&(isBoiled)) {
            isEmpty=true;
            isBoiled=false;
            System.out.println("锅炉啥都没有咯");
        }
    }
}

而后咱们测试下:

public class test {
    public static void main(String[] args) {
        ChocolateFactor factor=new ChocolateFactor();
        factor.fill();
        factor.boil();
        ChocolateFactor factor1=new ChocolateFactor();
        factor1.fill();
        factor1.boil();
    }
}

这里写图片描述
能够看到即便锅炉满了和沸腾了,其余人仍然能够往锅炉中添加,因此这是不合常理的,如今咱们来用单例试试:

public class ChocolateFactor {
    private boolean isEmpty;
    private boolean isBoiled;
    private static ChocolateFactor instance=null;
    private ChocolateFactor() {
        isEmpty=true;
        isBoiled=false;
    }
    public static ChocolateFactor getInstance(){
        if (instance==null) {
            instance=new ChocolateFactor();
        }
        return instance;
    }
    public void fill(){
        if (isEmpty) {
            isEmpty=false;
            isBoiled=false;
            System.out.println("锅炉满了");
        }
    }

    public void boil(){
        if ((!isEmpty)&&(!isBoiled)) {
            isBoiled=true;
            System.out.println("锅炉已经沸腾了");
        }
    }

    public void dump(){
        if ((!isEmpty)&&(isBoiled)) {
            isEmpty=true;
            isBoiled=false;
            System.out.println("锅炉啥都没有咯");
        }
    }
}

代码中能够看到咱们将构造方法私有化,提供一个静态的方法去返回巧克力工厂实例,将巧克力工厂静态化,使其在内存中只保留一份。如今咱们来测试下:

public class test {
    public static void main(String[] args) {
        ChocolateFactor factor=ChocolateFactor.getInstance();
        factor.fill();
        factor.boil();
        ChocolateFactor factor1=ChocolateFactor.getInstance();
        factor1.fill();
        factor1.boil();
    }
}

这里写图片描述
能够看到锅炉满了和沸腾以后对其再次操做是无效的。

可是其实这也是存在问题的,如今假设咱们在多线程的状态,线程一走到了if (instance==null) { 后cpu不让它工做了,开始线程二工做,线程二将整个getInstance走完了,如今cpu又让线程1执行,这时候,线程1又会去new 一个新的巧克力工厂,这样又产生了和第一个方式一样的问题,
在线程中咱们学过同步锁,咱们能够简单的在:

public static synchronized ChocolateFactor getInstance(){
        if (instance==null) {
            instance=new ChocolateFactor();
        }
        return instance;
    }

可是咱们知道加入synchronized 是很是耗内存的,因此这也不是咱们的最终解决办法,而后咱们再次看到另外一个解决办法:

public class ChocolateFactor {
    private boolean isEmpty;
    private boolean isBoiled;
// private static ChocolateFactor instance=null;
    private static ChocolateFactor instance=new ChocolateFactor();

    private ChocolateFactor() {
        isEmpty=true;
        isBoiled=false;
    }
// public static synchronized ChocolateFactor getInstance(){
// if (instance==null) {
// instance=new ChocolateFactor();
// }
// return instance;
// }
    public static synchronized ChocolateFactor getInstance(){
        return instance;
    }
    public void fill(){
        if (isEmpty) {
            isEmpty=false;
            isBoiled=false;
            System.out.println("锅炉满了");
        }
    }

    public void boil(){
        if ((!isEmpty)&&(!isBoiled)) {
            isBoiled=true;
            System.out.println("锅炉已经沸腾了");
        }
    }

    public void dump(){
        if ((!isEmpty)&&(isBoiled)) {
            isEmpty=true;
            isBoiled=false;
            System.out.println("锅炉啥都没有咯");
        }
    }
}

能够看到和以前的代码不一样的是咱们直接在定义变量的时候就直接将工厂new出来,而后在getInstance中直接返回,这种方式成为懒汉式,可是问题又来了,假如咱们不须要使用getInstance,而后在使用这个的类的时候咱们就已经在变量中直接将工厂new了出来,因此这样也是浪费了内存,那么咱们的最终解决办法是:

public static synchronized ChocolateFactor getInstance(){
        if (instance==null) {
            synchronized (ChocolateFactor.class) {
                if (instance==null) {
                    instance=new ChocolateFactor();
                }
            }
        }
        return instance;
    }

使用双重判断加锁的方式,如今咱们仍是在多线程的状态,加入线程1仍是在if (instance==null) { cpu不分配给它空间了,线程2开始工做,线程2一气呵成将getInstance走完,如今线程1工做了,线程走到
if (instance==null) 方法instance已经不为null了,因此他将不会再次new 一个,因此这才是咱们的终极方案。


—————————————————————————————————————————————

6、工厂模式

项目需求:生产披萨项目,生产披萨须要通过准备,烘烤,剪切,打包 4个步骤,根据客户输入的披萨名字生产对应的披萨。

首先用传统的方式去作:

public abstract class Pizza {
    protected String name;

    public abstract void prepare();
    public void bake()
    {
        System.out.println(name+" baking;");
    }
    public void cut()
    {
        System.out.println(name+" cutting;");
    }
    public void box()
    {
        System.out.println(name+" boxing;");
    }
    public void setname(String name)
    {
        this.name=name;
    }
}
public class PepperPizza extends Pizza{

    @Override
    public void prepare() {
        super.setname("PepperPizza");
        System.out.println("PepperPizza");
    }

}
public class GreekPizza extends Pizza{

    @Override
    public void prepare() {
        super.setname("GreekPizza");
        System.out.println("GreekPizza");
    }

}
public class CheesePizza extends Pizza{

    @Override
    public void prepare() {
        super.setname("CheesePizza");
        System.out.println("CheesePizza");
    }

}
public class OrderPizza {

    OrderPizza(){
        String type=null;
        Pizza pizza=null;
        do {
            type=getType();
            if (type.equals("greek")) {
                pizza=new GreekPizza();
            }else if (type.equals("cheese")) {
                pizza=new CheesePizza();
            }else if (type.equals("pepper")) {
                pizza=new PepperPizza();
            }else{
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }

    private String getType(){
        String type=null;
        BufferedReader br=null;
        try {
            br=new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            type= br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
        return type;
    }
}

代码分析:首先咱们考虑到生产披萨的4步骤是同样的,只有名字不同,因此咱们将名字方法抽象出来,友各个披萨类去实现,而后经过OrderPizza 类去模仿工厂生产的过程。

最后咱们来测试一下:

public class test {

    public static void main(String[] args) {
        OrderPizza order1=new OrderPizza();
    }

}

这里写图片描述

而后如今又研究出了几个新的披萨品种,须要加入到系统中,那么若是继续在传统的方式中修改,咱们只须要增长新品种披萨类,而后修改 OrderPizza 中的判断语句。

咱们如今用简单工厂模式下试一下:
简单工厂类中各类披萨类仍是同样,修改的是OrderPizza:

public class OrderPizza {

    OrderPizza(SimpleFactoryPizza factory){
        String type=null;
        Pizza pizza=null;
        do {
            type=getType();
            pizza=factory.createPizza(type);
            if (pizza!=null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else{
                break;
            }
        } while (true);
    }

    private String getType(){
        String type=null;
        BufferedReader br=null;
        try {
            br=new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            type= br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
        return type;
    }
}
public class SimpleFactoryPizza {
    public Pizza createPizza(String type){
        Pizza pizza=null;
        if (type.equals("greek")) {
            pizza=new GreekPizza();
        }else if (type.equals("cheese")) {
            pizza=new CheesePizza();
        }else if (type.equals("pepper")) {
            pizza=new PepperPizza();
        }else if (type.equals("beef")) {
            pizza=new BeefPizza();
        }
        return pizza;
    }
}

虽然看似代码是同样的,可是咱们已经将变化的代码抽取出来了,在OrderPizza中咱们无需再次修改,此时咱们已经将变化的和不变化的隔离开来了

而后如今咱们须要在纽约,伦敦生产披萨,且各地生成的披萨都各有差别,那么咱们如今使用工厂方法模式试试:

public class LDCheesePizza extends Pizza{

    @Override
    public void prepare() {
        super.setname("LDCheesePizza");
        System.out.println("LDCheesePizza");
    }

}
public class LDGreekPizza extends Pizza{

    @Override
    public void prepare() {
        super.setname("LDGreekPizza");
        System.out.println("LDGreekPizza");
    }

}
public class LDPepperPizza extends Pizza{

    @Override
    public void prepare() {
        super.setname("LDPepperPizza");
        System.out.println("LDPepperPizza");
    }

}

…纽约的也同样

咱们再来看看OrderPizza

public abstract class OrderPizza {

    public abstract Pizza createPizza(String type);
    public OrderPizza(){
        String type=null;
        Pizza pizza=null;
        do {
            type=getType();
            pizza=createPizza(type);
            if (pizza!=null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else{
                break;
            }
        } while (true);
    }

    private String getType(){
        String type=null;
        BufferedReader br=null;
        try {
            br=new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            type= br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
        return type;
    }
}

这里由于工厂是多样化的,因此这里咱们将工厂抽象,而后看具体实现:

public class NewYorkOrderPizza extends OrderPizza {

    @Override
    public Pizza createPizza(String type) {
        Pizza pizza=null;
        if (type.equals("greek")) {
            pizza=new LDGreekPizza();
        }else if (type.equals("cheese")) {
            pizza=new LDCheesePizza();
        }else if (type.equals("pepper")) {
            pizza=new LDPepperPizza();
        }
        return pizza;
    }

}
public class LondonOrderPizza extends OrderPizza {

    @Override
    public Pizza createPizza(String type) {
        Pizza pizza=null;
        if (type.equals("greek")) {
            pizza=new NYGreekPizza();
        }else if (type.equals("cheese")) {
            pizza=new NYCheesePizza();
        }else if (type.equals("pepper")) {
            pizza=new NYPepperPizza();
        }
        return pizza;
    }

}

最后咱们来测试一下

public class test {

    public static void main(String[] args) {
        OrderPizza order1=new NewYorkOrderPizza();
    }

}

这里写图片描述

最后咱们再试试使用抽象工厂模式:

public interface FactoryPizza {
    Pizza createPizza(String type);
}

单独将变化的工厂抽象

public class OrderPizza {

    OrderPizza(FactoryPizza factory){
        String type=null;
        Pizza pizza=null;
        do {
            type=getType();
            pizza=factory.createPizza(type);
            if (pizza!=null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }else{
                break;
            }
        } while (true);
    }

    private String getType(){
        String type=null;
        BufferedReader br=null;
        try {
            br=new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            type= br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
        return type;
    }
}
public class LondonFactoryPizza implements FactoryPizza{

    @Override
    public Pizza createPizza(String type) {
        Pizza pizza=null;
        if (type.equals("greek")) {
            pizza=new LDGreekPizza();
        }else if (type.equals("cheese")) {
            pizza=new LDCheesePizza();
        }else if (type.equals("pepper")) {
            pizza=new LDPepperPizza();
        }
        return pizza;
    }

}
public class NewYorkOrderPizza implements FactoryPizza{

    @Override
    public Pizza createPizza(String type) {
        Pizza pizza=null;
        if (type.equals("greek")) {
            pizza=new NYGreekPizza();
        }else if (type.equals("cheese")) {
            pizza=new NYCheesePizza();
        }else if (type.equals("pepper")) {
            pizza=new NYPepperPizza();
        }
        return pizza;

    }

}

效果和工厂方法模式是同样的,虽然这里可能看不出抽象工厂模式与工厂方法模式的差异,可是咱们在大的项目就能够看出来了


—————————————————————————————————————————————

7、命令模式

项目需求:智能家居,用户使用手机遥控操做灯,录音机。

好的,仍是先用传统的方式试试:

public class Light {

    String loc = "";

    public Light(String loc) {
        this.loc = loc;
    }

    public void On() {

        System.out.println(loc + " On");
    }

    public void Off() {

        System.out.println(loc + " Off");
    }

}
public class Stereo {
    static int volume = 0;

    public void On() {
        System.out.println("Stereo On");
    }

    public void Off() {
        System.out.println("Stereo Off");
    }

    public void SetCd() {
        System.out.println("Stereo SetCd");
    }

    public void SetVol(int vol) {
        volume = vol;
        System.out.println("Stereo volume=" + volume);
    }

    public int GetVol() {
        return volume;
    }

    public void Start() {
        System.out.println("Stereo Start");
    }
}
public interface Control {

    public void onButton(int slot);

    public void offButton(int slot);

    public void undoButton();
}
public class TraditionControl implements Control {
    Light light;
    Stereo stereo;

    public TraditionControl(Light light, Stereo stereo) {
        this.light = light;
        this.stereo = stereo;
    }

    @Override
    public void onButton(int slot) {
        // TODO Auto-generated method stub
        switch (slot) {
        case 0:
            light.On();
            break;
        case 1:
            stereo.On();
            break;
        case 2:
            int vol = stereo.GetVol();
            if (vol < 11) {
                stereo.SetVol(++vol);
            }
            break;
        }
    }

    @Override
    public void offButton(int slot) {
        // TODO Auto-generated method stub
        switch (slot) {
        case 0:
            light.Off();
            break;
        case 1:
            stereo.Off();
            break;
        case 2:
            int vol = stereo.GetVol();
            if (vol > 0) {
                stereo.SetVol(--vol);
            }
            break;
        }
    }

    @Override
    public void undoButton() {
        // TODO Auto-generated method stub

    }


}

传统的设计的比较死,TraditionControl 经过 onButton 与offButton分别传入一个tag值去控制,这里使用了Control 接口,便于管理。

下面测试一下:

public class test {

    public static void main(String[] args) {
        Light light=new Light("bedroom");
        Stereo stereo=new Stereo();
        TraditionControl tc=new TraditionControl(light, stereo);
        tc.onButton(0);
        tc.offButton(0);

        tc.onButton(1);
        tc.offButton(1);

        tc.onButton(2);
        tc.offButton(2);

        tc.offButton(1);
    }

}

这里写图片描述

如今假设录影机多了一个功能或者减小了一个功能,咱们须要去修改 Stereo 类,与之也要修改TraditionControl,这里看到修改一个类另一个类也须要修改,他们之间的耦合性过高了,因此下面使用命令模式:

public interface Command {
    public void execute();
    public void undo();
}
public class LightOffCommand implements Command {
    private Light light;
    public LightOffCommand(Light light)
    {
        this.light=light;
    }
    @Override
    public void execute() {
        // TODO Auto-generated method stub
        light.Off();
    }

    @Override
    public void undo() {
        // TODO Auto-generated method stub
        light.On();
    }

}
public class LightOnCommand implements Command {
    private Light light;

    public LightOnCommand(Light light)
    {
        this.light=light;

    }
    @Override
    public void execute() {
        // TODO Auto-generated method stub
        light.On();
    }

    @Override
    public void undo() {
        // TODO Auto-generated method stub
        light.Off();
    }

}
public class NoCommand implements Command {

    @Override
    public void execute() {
        // TODO Auto-generated method stub

    }

    @Override
    public void undo() {
        // TODO Auto-generated method stub

    }

}
public class StereoAddVolCommand implements Command {
    private Stereo stereo;

    public StereoAddVolCommand(Stereo stereo) {
        this.stereo = stereo;
    }

    @Override
    public void execute() {
        // TODO Auto-generated method stub
        int vol = stereo.GetVol();
        if (vol < 11) {
            stereo.SetVol(++vol);
        }

    }

    @Override
    public void undo() {
        // TODO Auto-generated method stub
        int vol = stereo.GetVol();
        if (vol > 0) {
            stereo.SetVol(--vol);
        }

    }

}
public class StereoSubVolCommand implements Command {
    private Stereo stereo;

    public StereoSubVolCommand(Stereo stereo) {
        this.stereo = stereo;
    }

    @Override
    public void execute() {
        // TODO Auto-generated method stub
        int vol = stereo.GetVol();
        if (vol > 0) {
            stereo.SetVol(--vol);
        }

    }

    @Override
    public void undo() {
        // TODO Auto-generated method stub
        int vol = stereo.GetVol();
        if (vol < 11) {
            stereo.SetVol(++vol);
        }

    }

}
public class StereoOffCommand implements Command {
    private Stereo stereo;
    public StereoOffCommand(Stereo stereo)
    {
        this.stereo=stereo;
    }

    @Override
    public void execute() {
        // TODO Auto-generated method stub
        stereo.Off();
    }

    @Override
    public void undo() {
        // TODO Auto-generated method stub
        stereo.On();
        stereo.SetCd();
    }

}
public class StereoOnCommand implements Command {
    private Stereo stereo;
    public StereoOnCommand(Stereo stereo)
    {
        this.stereo=stereo;
    }

    @Override
    public void execute() {
        // TODO Auto-generated method stub
        stereo.On();
        stereo.SetCd();

    }

    @Override
    public void undo() {
        // TODO Auto-generated method stub
        stereo.Off();
    }

}
public class MarcoCommand implements Command {

    private Command[] commands;

    public MarcoCommand(Command[] commands) {
        this.commands = commands;
    }

    @Override
    public void execute() {
        // TODO Auto-generated method stub
        for (int i = 0, len = commands.length; i < len; i++) {
            commands[i].execute();
        }
    }

    @Override
    public void undo() {
        // TODO Auto-generated method stub
        for (int i = commands.length - 1; i >= 0; i--) {
            commands[i].undo();

        }
    }

}

以上代码能够看出咱们将每一个命令单独写成一个类,若是须要增长新的命令也无需修改代码,只需相似上面去增长或者减小一个类

public class CommandModeControl implements Control{
    private Command[] onCommands;
    private Command[] offCommands;
    private Stack<Command> stack=new Stack<Command>();
    public CommandModeControl()
    {
        onCommands=new Command[5];
         offCommands=new Command[5];

         Command noCommand=new NoCommand();

         for(int i=0,len=onCommands.length;i<len;i++)
         {
             onCommands[i]=noCommand;
             offCommands[i]=noCommand;
         }

    }

    public void setCommand(int slot,Command onCommand,Command offCommand)
    {
        onCommands[slot]=onCommand;
         offCommands[slot]=offCommand;

    }

    @Override
    public void onButton(int slot) {

        onCommands[slot].execute();
        stack.push(onCommands[slot]);
    }

    @Override
    public void offButton(int slot) {

        offCommands[slot].execute();
        stack.push(offCommands[slot]);
    }

    @Override
    public void undoButton() {
        // TODO Auto-generated method stub
        stack.pop().undo();
    }

}

CommandModeControl控制类仍是继承自Control,经过其自身的setCommand方法将所需执行的命令添加到数组中,固然这里限定数组的大小是5,读者也能够写个1024之类的,假如须要的话。

下面看看测试的效果:

public class test {

    public static void main(String[] args) {
        Light bedroomLight=new Light("bedroom");
        LightOnCommand lightOnCommand=new LightOnCommand(bedroomLight);
        LightOffCommand lightOffCommand=new LightOffCommand(bedroomLight);
        Stereo stereo=new Stereo();
        StereoOnCommand stereoOnCommand=new StereoOnCommand(stereo);
        StereoOffCommand stereoOffCommand=new StereoOffCommand(stereo);
        StereoAddVolCommand addVolCommand=new StereoAddVolCommand(stereo);
        StereoSubVolCommand subVolCommand=new StereoSubVolCommand(stereo);

        Command[] commands1={lightOnCommand,stereoOnCommand,addVolCommand};
        Command[] commands2={lightOffCommand,stereoOffCommand,subVolCommand};
        MarcoCommand onMarcoCommand=new MarcoCommand(commands1);
        MarcoCommand offMarcoCommand=new MarcoCommand(commands2);

        CommandModeControl control=new CommandModeControl();
        control.setCommand(0, lightOnCommand, lightOffCommand);
        control.onButton(0);
        control.offButton(0);

        control.setCommand(1, stereoOnCommand, stereoOffCommand);
        control.onButton(1);
        control.offButton(1);

        control.setCommand(2, addVolCommand, subVolCommand);
        control.onButton(2);
        control.onButton(2);
        control.onButton(2);
        control.offButton(2);
        control.undoButton();

        control.setCommand(3, onMarcoCommand, offMarcoCommand);
        control.onButton(3);
        control.offButton(3);

    }

}

这里写图片描述

经过使用命令模式能够看到类与类之间是彻底没有耦合性的


—————————————————————————————————————————————

8、适配器模式

适配器通俗易懂至关于就是一个转换器,平时手机充电,假如这个头不能插入手机,咱们只须要经过一个转换器,而后使用转换器上的插头便可。

如今有一个火鸡基地,他们想吃鸭子,他们就能够经过一个转换器:

public interface Turkey {

    public void gobble();
    public void fly();

}
public class WildTurkey implements Turkey {

    @Override
    public void gobble() {
        // TODO Auto-generated method stub
        System.out.println(" Go Go");
    }

    @Override
    public void fly() {
        // TODO Auto-generated method stub
        System.out.println("I am flying a short distance");
    }

}
public interface Duck {
    public void quack();
    public void fly();
}
public class GreenHeadDuck implements Duck {

    @Override
    public void quack() {
        // TODO Auto-generated method stub
        System.out.println(" Ga Ga");
    }

    @Override
    public void fly() {
        // TODO Auto-generated method stub
        System.out.println("I am flying a long distance");
    }

}
public class TurkeyAdapter implements Duck {
    private Turkey turkey;

    public TurkeyAdapter(Turkey turkey)
    {
        this.turkey=turkey;
    }

    @Override
    public void quack() {
        // TODO Auto-generated method stub
        turkey.gobble();
    }

    @Override
    public void fly() {
        // TODO Auto-generated method stub
        for(int i=0;i<3;i++)
        {
            turkey.fly();
        }
    }

}

适配器经过实现鸭子类的方法,实现的是火鸡的方法,

下面咱们来测试下:

public class test {
    public static void main(String[] args) {
        GreenHeadDuck greenHeadDuck=new GreenHeadDuck();
        greenHeadDuck.quack();
        greenHeadDuck.fly();

        WildTurkey wildTurkey=new WildTurkey();
        wildTurkey.gobble();
        wildTurkey.fly();

        TurkeyAdapter adapter=new TurkeyAdapter(wildTurkey);
        adapter.quack();
        adapter.fly();
    }
}

这里写图片描述

这种适配器模式称为对象适配器,下面咱们来介绍类适配器:

public class TurkeyAdapter extends WildTurkey implements Duck {

    @Override
    public void quack() {
        // TODO Auto-generated method stub
        super.gobble();
    }
    @Override
    public void fly() {
        // TODO Auto-generated method stub
        super.fly();
        super.fly();
        super.fly();
    }
}

实现鸭子类并继承火鸡类,以前咱们说过要少使用继承,因此咱们这里仍是推荐使用对象适配器。

来测试下:

public class test {
    public static void main(String[] args) {
        GreenHeadDuck greenHeadDuck=new GreenHeadDuck();
        greenHeadDuck.quack();
        greenHeadDuck.fly();

        WildTurkey wildTurkey=new WildTurkey();
        wildTurkey.gobble();
        wildTurkey.fly();

        TurkeyAdapter adapter=new TurkeyAdapter();
        adapter.quack();
        adapter.fly();
    }
}

这里写图片描述

能够看到效果是一摸同样,以前咱们在java集合遍历使用的是枚举器,后来出现了迭代器,若是想用枚举器兼容迭代器,咱们能够这样作:

public class EnumerationIterator implements Iterator<Object> {

    private Enumeration enumeration;

    public EnumerationIterator(Enumeration enumeration)
    {
         this.enumeration= enumeration;
    }

    @Override
    public boolean hasNext() {
        // TODO Auto-generated method stub
        return enumeration.hasMoreElements();
    }

    @Override
    public Object next() {
        // TODO Auto-generated method stub
        return enumeration.nextElement();
    }

    @Override
    public void remove() {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException();
    }

}


—————————————————————————————————————————————

9、外观模式

项目需求,家庭电影院,大概有一个这样的过程
直接用遥控器:统筹各设备开关
开爆米花机
放下屏幕
开投影仪
开音响
开DVD,选dvd
去拿爆米花
调暗灯光
播放
观影结束后,关闭各类设备

public class DVDPlayer {



    private static DVDPlayer instance = null;

    private DVDPlayer() {

    }

    public static DVDPlayer getInstance() {
        if (instance == null) {
            instance = new DVDPlayer();
        }

        return instance;
    }

    public void on() {
        System.out.println("DVDPlayer On");
    }

    public void off() {
        System.out.println("DVDPlayer Off");
    }

    public void play() {
        System.out.println("DVDPlayer is playing");
    }

    public void pause() {
        System.out.println("DVDPlayer pause");
    }

    public void setdvd() {
        System.out.println("DVDPlayer is setting dvd");
    }
}
public class Popcorn {


    private static Popcorn instance = null;

    private Popcorn() {

    }

    public static Popcorn getInstance() {
        if (instance == null) {
            instance = new Popcorn();
        }

        return instance;
    }

    public void on() {
        System.out.println("Popcorn On");
    }

    public void off() {
        System.out.println("Popcorn Off");
    }

    public void pop() {
        System.out.println("Popcorn is popping");
    }



}
public class Projector {
    private int size=5;

    private static Projector instance = null;

    private Projector() {

    }

    public static Projector getInstance() {
        if (instance == null) {
            instance = new Projector();
        }

        return instance;
    }

    public void on() {
        System.out.println("Projector On");
    }

    public void off() {
        System.out.println("Projector Off");
    }

    public void focus() {
        System.out.println("Projector is focus");
    }

    public void zoom(int size) {
        this.size=size;
        System.out.println("Projector zoom to"+size);
    }

}
public class Screen {

    private static Screen instance = null;

    private Screen() {

    }

    public static Screen getInstance() {
        if (instance == null) {
            instance = new Screen();
        }

        return instance;
    }

    public void up() {
        System.out.println("Screen up");
    }

    public void down() {
        System.out.println("Screen down");
    }

}
public class Stereo {

    private static Stereo instance = null;
    private int volume = 5;

    private Stereo() {

    }

    public static Stereo getInstance() {
        if (instance == null) {
            instance = new Stereo();
        }

        return instance;
    }

    public void on() {
        System.out.println("Stereo On");
    }

    public void off() {
        System.out.println("Stereo Off");
    }

    public void setVolume(int vol) {

        volume = vol;
        System.out.println("the volume of Stereo is set to " + volume);
    }

    public void addVolume() {
        if (volume < 11) {
            volume++;
            setVolume(volume);
        }

    }

    public void subVolume() {
        if (volume > 0) {
            volume--;
            setVolume(volume);
        }

    }

}
public class TheaterLights {

    private static TheaterLights instance = null;

    private TheaterLights() {

    }

    public static TheaterLights getInstance() {
        if (instance == null) {
            instance = new TheaterLights();
        }

        return instance;
    }

    public void on() {
        System.out.println("TheaterLights On");
    }

    public void off() {
        System.out.println("TheaterLights Off");
    }

    public void dim(int d) {
        System.out.println("TheaterLights dim to " + d + "%");
    }

    public void bright() {
        dim(100);
        System.out.println("TheaterLights bright");
    }
}

以上就是将每一个须要的功能封装成一个类具体实现,加入咱们不使用外观模式,则须要当使用每一个类的时候就要去调用相应的函数,咱们看外观模式怎么实现:

public class HomeTheaterFacade {
    private TheaterLights mTheaterLights;
    private Popcorn mPopcorn;
    private Stereo mStereo;
    private Projector mProjector;
    private Screen mScreen;
    private DVDPlayer mDVDPlayer;

    public HomeTheaterFacade() {
        mTheaterLights = TheaterLights.getInstance();
        mPopcorn = Popcorn.getInstance();
        mStereo = Stereo.getInstance();
        mProjector = Projector.getInstance();
        mScreen = Screen.getInstance();
        mDVDPlayer = DVDPlayer.getInstance();
    }

    public void ready() {
        mPopcorn.on();
        mPopcorn.pop();
        mScreen.down();
        mProjector.on();
        mStereo.on();
        mDVDPlayer.on();
        mDVDPlayer.setdvd();
        mTheaterLights.dim(10);
    }

    public void end() {
        mPopcorn.off();
        mTheaterLights.bright();
        mScreen.up();
        mProjector.off();
        mStereo.off();

        mDVDPlayer.setdvd();
        mDVDPlayer.off();

    }

    public void play() {
        mDVDPlayer.play();
    }

    public void pause() {
        mDVDPlayer.pause();
    }
}

从代码中能够看打咱们是将一系列相同的操做封装在一个遥控器中,这样就不用每一个功能去使用一个遥控器,大大简化了操做,外观模式遵循的是最少知识原则,所谓最少知识原则是将关联紧切的一些函数在一块儿使用,尽可能减小对象之间的交互,只留几个“密友”。

测试一下:

public class test {

    public static void main(String[] args) {
        HomeTheaterFacade mHomeTheaterFacade=new HomeTheaterFacade();

        mHomeTheaterFacade.ready();
        mHomeTheaterFacade.play();
    }
}

这里写图片描述


—————————————————————————————————————————————

10、模板模式

冲咖啡和泡茶过程的描述:煮沸水,酝酿,倒入杯子,加入佐料,下面看代码:

public class Coffee {

    public void prepareRecipe(){
        boilWater();
        brewCoffee();
        pourInCup();
        addSugarMilk();
    }

    private void addSugarMilk() {
        System.out.println("增长牛奶和糖");
    }

    private void pourInCup() {
        System.out.println("倒入杯子");
    }

    private void brewCoffee() {
        System.out.println("酝酿咖啡");
    }

    private void boilWater() {
        System.out.println("煮沸水");
    }
}
public class Tea {

    public void prepareRecipe(){
        boilWater();
        brewCoffee();
        pourInCup();
        addLemon();
    }

    private void addLemon() {
        System.out.println("增长柠檬");
    }

    private void pourInCup() {
        System.out.println("倒入杯子");
    }

    private void brewCoffee() {
        System.out.println("酝酿茶");
    }

    private void boilWater() {
        System.out.println("煮沸水");
    }
}

其中泡茶和冲咖啡的煮沸水和倒入杯子步骤是相通的,而后最后在优化一下:

public class HotDrink {

    public void pourInCup() {
        System.out.println("倒入杯子");
    }
    public void boilWater() {
        System.out.println("煮沸水");
    }
}
public class Coffee extends HotDrink{

    public void prepareRecipe(){
        super.boilWater();
        brewCoffee();
        super.pourInCup();
        addSugarMilk();
    }

    private void addSugarMilk() {
        System.out.println("增长牛奶和糖");
    }

    private void brewCoffee() {
        System.out.println("酝酿咖啡");
    }
}
public class Tea extends HotDrink{

    public void prepareRecipe(){
        super.boilWater();
        brewCoffee();
        super.pourInCup();
        addLemon();
    }

    private void addLemon() {
        System.out.println("增长柠檬");
    }

    private void brewCoffee() {
        System.out.println("酝酿茶");
    }
}

很是简单一个代码设计,测试一下:

public class test {

    public static void main(String[] args) {
        Coffee coffee=new Coffee();
        coffee.prepareRecipe();

        Tea tea=new Tea();
        tea.prepareRecipe();

    }

}

这里写图片描述

咱们在仔细对比一下会发现,冲咖啡和泡茶的4个步骤大体也是一致的,因此咱们能够再次抽取:

public abstract class HotDrink {

    public final void prepareRecipe(){
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }
    public final void boilWater() {
        System.out.println("煮沸水");
    }

    public abstract void brew();

    public final void pourInCup() {
        System.out.println("倒入杯子");
    }

    public abstract void addCondiments();


}
public class Coffee extends HotDrink{

    @Override
    public void brew() {
        System.out.println("酝酿咖啡");

    }

    @Override
    public void addCondiments() {
        System.out.println("增长糖和牛奶");

    }


}
public class Tea extends HotDrink{

    @Override
    public void brew() {
        System.out.println("酝酿茶");
    }

    @Override
    public void addCondiments() {
        System.out.println("增长柠檬");
    }


}

这就是使用了模板模式,将一系列算法的步骤或者流程封装在一个方法,将相同的步骤实现,不一样的步骤抽象,更好的模板模式会提供一个钩子:

public abstract class HotDrink {

    public final void prepareRecipe(){
        boilWater();
        brew();
        pourInCup();
        if (isNeedCondiments()) {
            addCondiments();
        }else{
            System.out.println("not need condiments");
        }

    }
    public final void boilWater() {
        System.out.println("煮沸水");
    }

    public abstract void brew();

    public final void pourInCup() {
        System.out.println("倒入杯子");
    }

    public abstract void addCondiments();

    public boolean isNeedCondiments(){
        return true;
    }

}

这里的isNeedCondiments()方法就是一个钩子,子类能够重写这个方法以判断是否须要:

public class Coffee extends HotDrink{

    @Override
    public void brew() {
        System.out.println("酝酿咖啡");

    }

    @Override
    public void addCondiments() {
        System.out.println("增长糖和牛奶");

    }

    @Override
    public boolean isNeedCondiments() {
        String tagStr=null;
        boolean tag=true;
        System.out.println("请输入是否须要佐料:(y/n)");
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        try {
            tagStr=br.readLine();
            if (tagStr.equals("n")) {
                tag=false;
            }
        } catch (IOException e) {
            tag=false;
            e.printStackTrace();
        }
        return tag;
    }


}

这里咖啡重写钩子方法,经过用户输入y/n去判断是否须要佐料

在Java和android中其实不少地方用到了模板模式,将一个具体的算法步骤后者流程封装在一个方法体现出来,例如咱们模拟燕子排序:

public class Duck implements Comparable<Duck>{
    private int weight;
    private int height;

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public Duck(int weight,int height) {
        this.weight=weight;
        this.height=height;
    }

    @Override
    public int compareTo(Duck o) {
        if (this.weight>o.weight) {
            return 1;
        }else{
            return -1;
        }
    }

}
public class test {

    public static void main(String[] args) {
        Duck[] ducks={new Duck(5, 6),new Duck(1, 2),new Duck(3, 4),new Duck(0, 0)};
        bianli(ducks);
        Arrays.sort(ducks);
        System.out.println("排序后");
        bianli(ducks);
    }

    private static void bianli(Duck[] ducks){
        for (int i = 0; i < ducks.length; i++) {
            Duck duck=ducks[i];
            System.out.println(duck.getWeight());
        }
    }
}

这里写图片描述

鸭子排序咱们不须要排序的具体步骤,高层不须要知道底层的具体实现。

在Android中的BaseAdpater,经过getCount,getItem…等等一些列流程Andriod都将这个步骤怎么走的封装好了,再例如Activity的生命周期,Android也都将步骤都给封装好了。


—————————————————————————————————————————————

11、迭代器模式

项目需求:蛋糕店和餐厅的菜单项目:

public class MenuItem {
    private String name,description;
    private boolean vegetable;
    private float price;
    public MenuItem(String name,String description,boolean vegetable,float price)
    {
        this.name=name;
        this.description=description;
        this.vegetable=vegetable;
        this.price=price;

    }
    public String getName()
    {
        return name;
    }
    public String getDescription()
    {
        return description;
    }
    public float getPrice()
    {
        return price;
    }
    public boolean  isVegetable()
    {
        return vegetable;
    }
}
public class CakeHouseMenu {
    private ArrayList<MenuItem> menuItems;

    public CakeHouseMenu() {
        menuItems = new ArrayList<MenuItem>();

        addItem("KFC Cake Breakfast","boiled eggs&toast&cabbage",true,3.99f);
        addItem("MDL Cake Breakfast","fried eggs&toast",false,3.59f);
        addItem("Stawberry Cake","fresh stawberry",true,3.29f);
        addItem("Regular Cake Breakfast","toast&sausage",true,2.59f);
    }

    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        menuItems.add(menuItem);
    }
    public ArrayList<MenuItem> getMenuItems() {
        return menuItems;
    }

}
public class DinerMenu {
    private final static int Max_Items=5;
    public int numberOfItems=0;
    private MenuItem[] menuItems;

    public DinerMenu()
    {
        menuItems=new MenuItem[Max_Items] ;
        addItem("vegetable Blt","bacon&lettuce&tomato&cabbage",true,3.58f);
        addItem("Blt","bacon&lettuce&tomato",false,3.00f);
        addItem("bean soup","bean&potato salad",true,3.28f);
        addItem("hotdog","onions&cheese&bread",false,3.05f);


    }
    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        if(numberOfItems>=Max_Items)
        {
            System.err.println("sorry,menu is full!can not add another item");
        }else{
            menuItems[numberOfItems]=menuItem;
            numberOfItems++;
        }

    }

    public MenuItem[] getMenuItems() {
        return menuItems;
    }
}

分析代码:蛋糕店经过一个集合去增长菜单,提供公有的方法getMenuItems返回集合,而餐厅采用的是数组去增长菜单,并设置其最大的菜单数为5,提供公有的方法getMenuItems返回数组

咱们再经过一个服务员去打印两个的菜单:

public class Waitress {
    private CakeHouseMenu mCakeHouseMenu;
    private DinerMenu mDinerMenu;
    private ArrayList<MenuItem> cakeitems;
    private MenuItem[] dineritems;



    public Waitress() {
        mCakeHouseMenu = new CakeHouseMenu();
        cakeitems = mCakeHouseMenu.getMenuItems();

        mDinerMenu = new DinerMenu();
        dineritems = mDinerMenu.getMenuItems();
    }

    public void printMenu() {
        MenuItem menuItem;
        for (int i = 0, len = cakeitems.size(); i < len; i++) {
            menuItem = cakeitems.get(i);
            System.out.println(menuItem.getName() + "***"
                    +menuItem.getPrice()+"***"+ menuItem.getDescription());

        }
        for (int i = 0, len = mDinerMenu.numberOfItems; i < len; i++) {
            menuItem = dineritems[i];
            System.out.println(menuItem.getName() + "***"
                    +menuItem.getPrice()+"***"+ menuItem.getDescription());

        }

    }
}

服务员经过他们的公共的方法得到餐厅和蛋糕店的菜单数组和集合,而后采用for循环遍历出来。

测试代码:

public class test {

    public static void main(String[] args) {

        Waitress mWaitress=new Waitress();

        mWaitress.printMenu();
    }
}

如今咱们须要将两个餐厅合并,可是咱们能够看到一个是采用数组增长菜单,一个是采用集合的方式,因此如今引出了迭代器模式,提供一种方法顺序访问一个聚合对象中的各个对象

public interface Iterator {

    public boolean hasNext();
    public Object next();


}
public class CakeHouseMenu {
    private ArrayList<MenuItem> menuItems;

    public CakeHouseMenu() {
        menuItems = new ArrayList<MenuItem>();

        addItem("KFC Cake Breakfast", "boiled eggs&toast&cabbage", true, 3.99f);
        addItem("MDL Cake Breakfast", "fried eggs&toast", false, 3.59f);
        addItem("Stawberry Cake", "fresh stawberry", true, 3.29f);
        addItem("Regular Cake Breakfast", "toast&sausage", true, 2.59f);
    }

    private void addItem(String name, String description, boolean vegetable, float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        menuItems.add(menuItem);
    }

    public Iterator getIterator() {
        return new CakeHouseIterator();
    }

    class CakeHouseIterator implements Iterator {
        private int position = 0;

        public CakeHouseIterator() {
            position = 0;
        }

        @Override
        public boolean hasNext() {
            // TODO Auto-generated method stub
            if (position < menuItems.size()) {
                return true;
            }

            return false;
        }

        @Override
        public Object next() {
            // TODO Auto-generated method stub
            MenuItem menuItem = menuItems.get(position);
            position++;
            return menuItem;
        }
    };

}
public class DinerMenu {
    private final static int Max_Items = 5;
    private int numberOfItems = 0;
    private MenuItem[] menuItems;

    public DinerMenu() {
        menuItems = new MenuItem[Max_Items];
        addItem("vegetable Blt", "bacon&lettuce&tomato&cabbage", true, 3.58f);
        addItem("Blt", "bacon&lettuce&tomato", false, 3.00f);
        addItem("bean soup", "bean&potato salad", true, 3.28f);
        addItem("hotdog", "onions&cheese&bread", false, 3.05f);

    }

    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        if (numberOfItems >= Max_Items) {
            System.err.println("sorry,menu is full!can not add another item");
        } else {
            menuItems[numberOfItems] = menuItem;
            numberOfItems++;
        }

    }

    public Iterator getIterator() {
        return new DinerIterator();
    }

    class DinerIterator implements Iterator {
        private int position;

        public DinerIterator() {
            position = 0;
        }

        @Override
        public boolean hasNext() {
            // TODO Auto-generated method stub
            if (position < numberOfItems) {
                return true;
            }

            return false;
        }

        @Override
        public Object next() {
            // TODO Auto-generated method stub
            MenuItem menuItem = menuItems[position];
            position++;
            return menuItem;
        }
    };
}

分析代码:以前咱们是将各个店封装菜单的容器给提供出去,如今咱们是将各类容器变成一个迭代接口,经过两个方法去遍历,因此如今外界无需知道咱们的每一个店具体是采用什么容器去封装菜单:

public class Waitress {
    private ArrayList<Iterator> iterators=new ArrayList<Iterator>();


    public Waitress() {

    }
    public void addIterator(Iterator iterator)
    {
        iterators.add(iterator);

    }
    public void printMenu() {
        Iterator iterator;
        MenuItem menuItem;
        for (int i = 0, len = iterators.size(); i < len; i++) {
            iterator = iterators.get(i);

            while(iterator.hasNext())
            {
                menuItem=(MenuItem) iterator.next();
                System.out.println(menuItem.getName() + "***"
                        +menuItem.getPrice()+"***"+ menuItem.getDescription());

            }


        }



    }


}

在蛋糕店和餐厅咱们将他们的菜单容器都转化成一个迭代器,而后服务员类只须要获得他们各自转变后的迭代器,并使用迭代器提供的方法去遍历,无需知道具体的容器类型,也将餐厅,蛋糕店与服务员隔离,低耦合度,在以前咱们是须要在服务员类中拿到两个店类,这样的话耦合度就高

如今来测试下:

public class MainTest {
    public static void main(String[] args) {
        Waitress mWaitress=new Waitress();
        CakeHouseMenu mCakeHouseMenu = new CakeHouseMenu();
        DinerMenu   mDinerMenu = new DinerMenu();

        mWaitress.addIterator(mCakeHouseMenu.getIterator());
        mWaitress.addIterator(mDinerMenu.getIterator());
        mWaitress.printMenu();
    }
}

最后咱们在使用Java内置的迭代器试试,刚才咱们本身定了一个接口Iterator,:

public class DinerMenu {
    private final static int Max_Items = 5;
    private int numberOfItems = 0;
    private MenuItem[] menuItems;

    public DinerMenu() {
        menuItems = new MenuItem[Max_Items];
        addItem("vegetable Blt", "bacon&lettuce&tomato&cabbage", true, 3.58f);
        addItem("Blt", "bacon&lettuce&tomato", false, 3.00f);
        addItem("bean soup", "bean&potato salad", true, 3.28f);
        addItem("hotdog", "onions&cheese&bread", false, 3.05f);

    }

    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        if (numberOfItems >= Max_Items) {
            System.err.println("sorry,menu is full!can not add another item");
        } else {
            menuItems[numberOfItems] = menuItem;
            numberOfItems++;
        }

    }

    public Iterator getIterator() {
        return new DinerIterator();
    }

    class DinerIterator implements Iterator {
        private int position = 0;

        @Override
        public boolean hasNext() {
            // TODO Auto-generated method stub
            if (position < numberOfItems) {
                return true;
            }
            position = 0;
            return false;
        }

        @Override
        public Object next() {
            // TODO Auto-generated method stub
            MenuItem menuItem = menuItems[position];
            position++;
            return menuItem;
        }

        @Override
        public void remove() {
            // TODO Auto-generated method stub

        }

    }
}
public class CakeHouseMenu {
    private ArrayList<MenuItem> menuItems;
    private int position=0;
    public CakeHouseMenu() {
        menuItems = new ArrayList<MenuItem>();

        addItem("KFC Cake Breakfast","boiled eggs&toast&cabbage",true,3.99f);
        addItem("MDL Cake Breakfast","fried eggs&toast",false,3.59f);
        addItem("Stawberry Cake","fresh stawberry",true,3.29f);
        addItem("Regular Cake Breakfast","toast&sausage",true,2.59f);
    }

    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        menuItems.add(menuItem);
    }



    public Iterator getIterator()
    {
        return menuItems.iterator();
    }


}

如今咱们这是都是使用了Java内置的迭代器,由于ArrayList中自己有迭代器,因此代码中是直接返回。服务员类代码仍是同样,这里就不继续贴出来了。

如今咱们须要增长一个咖啡店的菜单:

public class CafeMenu {
    private Hashtable<String,MenuItem> menuItems=new Hashtable<String,MenuItem>(); 

    public CafeMenu()
    {
        addItem("Moca Burger","moca&bruger&tomato",true,3.56f);
        addItem("Soup Latte","Latte&salad&soup",true,3.26f);
        addItem("Burrito","bacon&toamto&beans",false,3.96f);

    }
    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        menuItems.put(name, menuItem);

    }



    public Iterator getIterator()
    {
        return menuItems.values().iterator();
    }
}

该咖啡店采用的是Hashtable方式增长集合,可是经过迭代器模式咱们不须要知道这个,能够很好的将新增的咖啡店菜单融合在一块儿。


—————————————————————————————————————————————

12、组合模式

在上一节迭代模式中咱们使用迭代器的方式将各个餐厅的菜单项结合在一块儿,如今咱们继续在这个项目中增长需求,如今须要在菜单中添加一个子菜单,子菜单包括菜单项,首先下分析一下这个问题:
这里写图片描述

这里写图片描述

如今经过代码来看一下:

public abstract class MenuComponent {

    public String getName() {
        return "";
    }

    public String getDescription() {
        return "";
    }

    public float getPrice() {
        return 0;
    }

    public boolean isVegetable() {
        return false;
    }

    public abstract void print();

    public Iterator getIterator() {
        return new NullIterator();
    }
}
public class MenuItem extends MenuComponent{
    private String name,description;
    private boolean vegetable;
    private float price;
    public MenuItem(String name,String description,boolean vegetable,float price)
    {
        this.name=name;
        this.description=description;
        this.vegetable=vegetable;
        this.price=price;

    }
    @Override
    public String getName()
    {
        return name;
    }
    @Override
    public String getDescription()
    {
        return description;
    }
    @Override
    public float getPrice()
    {
        return price;
    }
    @Override
    public boolean  isVegetable()
    {
        return vegetable;
    }
    @Override
    public void print() {
        // TODO Auto-generated method stub
        System.out.println(getName() + "***" + getPrice() + "***"
                + getDescription());

    }
}
public class NullIterator implements Iterator{

    @Override
    public boolean hasNext() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public Object next() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void remove() {
        // TODO Auto-generated method stub

    }

}

分析代码:设定一个抽象的父类MenuComponent,让不管是菜单,仍是菜单项MenuItem都去继承它,经过print去打印信息,getIterator去获得迭代器,若是遍历出来的MenuComponent是MenuItem则迭代器为NullIterator,和咱们以前的命令模式中的NoCommand是同样的,表示没有迭代器,若是是菜单或者子菜单是会获得一个迭代器的,其余代码和迭代器模式中仍是没有改变。

下面咱们看看菜单和子菜单的代码:

public class CakeHouseMenu extends MenuComponent {
    private ArrayList<MenuComponent> menuItems;

    public CakeHouseMenu() {
        menuItems = new ArrayList<MenuComponent>();

        addItem("KFC Cake Breakfast", "boiled eggs&toast&cabbage", true, 3.99f);
        addItem("MDL Cake Breakfast", "fried eggs&toast", false, 3.59f);
        addItem("Stawberry Cake", "fresh stawberry", true, 3.29f);
        addItem("Regular Cake Breakfast", "toast&sausage", true, 2.59f);
    }

    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        menuItems.add(menuItem);
    }

    public Iterator getIterator() {
        return new ComposeIterator(menuItems.iterator());
    }

    @Override
    public void print() {
        // TODO Auto-generated method stub
        System.out.println("****This is CakeHouseMenu****");
    };


}
public class SubMenu extends MenuComponent {
    private ArrayList<MenuComponent> menuItems;

    public SubMenu() {
        menuItems = new ArrayList<MenuComponent>();

        addItem("Apple Cookie", "Apple&candy&Cookie", true, 1.99f);
        addItem("Banana Cookie", "Banana&candy&Cookie", false, 1.59f);
        addItem("Orange Cookie", "Orange&Cookie", true, 1.29f);
    }

    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        menuItems.add(menuItem);
    }

    public Iterator getIterator() {
        return new ComposeIterator(menuItems.iterator());
    }

    @Override
    public void print() {
        // TODO Auto-generated method stub
        System.out.println("****This is SubMenu****");
    };

}
public class DinerMenu extends MenuComponent {
    private final static int Max_Items = 5;
    private int numberOfItems = 0;
    private MenuComponent[] menuItems;

    public DinerMenu() {
        menuItems = new MenuComponent[Max_Items];
        addItem("vegetable Blt", "bacon&lettuce&tomato&cabbage", true, 3.58f);
        addItem("Blt", "bacon&lettuce&tomato", false, 3.00f);
        addItem("bean soup", "bean&potato salad", true, 3.28f);
        addItem("hotdog", "onions&cheese&bread", false, 3.05f);
        addSubMenu(new SubMenu());

    }

    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        if (numberOfItems >= Max_Items) {
            System.err.println("sorry,menu is full!can not add another item");
        } else {
            menuItems[numberOfItems] = menuItem;
            numberOfItems++;
        }

    }
    private void addSubMenu(MenuComponent mMenuComponent) {
        if (numberOfItems >= Max_Items) {
            System.err.println("sorry,menu is full!can not add another item");
        } else {
            menuItems[numberOfItems] = mMenuComponent;
            numberOfItems++;
        }

    }
    public Iterator getIterator() {
        return new ComposeIterator(new DinerIterator());
    }

    class DinerIterator implements Iterator {
        private int position;

        public DinerIterator() {
            position = 0;
        }

        @Override
        public boolean hasNext() {
            // TODO Auto-generated method stub
            if (position < numberOfItems) {
                return true;
            }

            return false;
        }

        @Override
        public Object next() {
            // TODO Auto-generated method stub
            MenuComponent menuItem = menuItems[position];
            position++;
            return menuItem;
        }

        @Override
        public void remove() {
            // TODO Auto-generated method stub

        }
    }

    @Override
    public void print() {
        // TODO Auto-generated method stub
        System.out.println("****This is DinerMenu****");
    };
}

代码分析:菜单,子菜单也继承自MenuComponent ,由于子菜单和菜单中包含MenuItem,因此它们都有各自的Iterator返回,Iterator的处理和以前的迭代器模式也是同样,只是咱们如今经过了ComposeIterator类去包装它们的Iteraotr,并且转变成Iterator的各个菜单的菜单项容器装的也是MenuComponent ,这样的话,能够保持菜单中既能够装子菜单也能够装MenuItem,由于它们都是继承自父类MenuComponent ,这样作到了很好的延伸,,目前咱们已经将迭代器封装好了,如今咱们看看ComposeIterator的处理逻辑:

public class ComposeIterator implements Iterator {
    private Stack<Iterator> stack = new Stack<Iterator>();

    public ComposeIterator(Iterator iterator) {
        stack.push(iterator);
    }

    @Override
    public boolean hasNext() {
        // TODO Auto-generated method stub
        if (stack.empty()) {
            return false;
        }
        Iterator iterator = stack.peek();
        if (!iterator.hasNext()) {
            stack.pop();
            return hasNext();
        } else {
            return true;
        }
    }

    @Override
    public Object next() {
        // TODO Auto-generated method stub
        if (hasNext()) {
            Iterator iterator = stack.peek();
            MenuComponent mMenuComponent = (MenuComponent) iterator.next();
            stack.push(mMenuComponent.getIterator());
            return mMenuComponent;
        }
        return null;
    }

    @Override
    public void remove() {
        // TODO Auto-generated method stub

    }

}

ComposeIterator 继承自Iterator,在构造中传入菜单各自的Iterator,使用堆栈Stack push ,经过重写hasNext()去判断Stack 中的Iterator是否有元素,没有元素的话pop出去,而后在经过迭代hasNext()方法,继续判断,经过重写next()方法去返回Iterator中的每个MenuComponent ,而后将每个MenuComponent 的iterator 经过Stack push,假如MenuComponent 是SubMenu,则有Iterator,若是是MenuItem则我NullIterator,在hasNext()中pop掉。

下面咱们看看服务员类怎么遍历:

public class Waitress {
    private ArrayList<MenuComponent> iterators = new ArrayList<MenuComponent>();

    public Waitress() {

    }

    public void addComponent(MenuComponent mMenuComponent) {
        iterators.add(mMenuComponent);

    }

    public void printMenu() {
        Iterator iterator;
        MenuComponent menuItem;
        for (int i = 0, len = iterators.size(); i < len; i++) {
            iterators.get(i).print();
            iterator = iterators.get(i).getIterator();

            while (iterator.hasNext()) {
                menuItem = (MenuComponent) iterator.next();
                menuItem.print();
            }

        }

    }

    public void printBreakfastMenu() {

    }

    public void printLunchMenu() {

    }

    public void printVegetableMenu() {

        Iterator iterator;
        MenuComponent menuItem;
        for (int i = 0, len = iterators.size(); i < len; i++) {
            iterators.get(i).print();
            iterator = iterators.get(i).getIterator();

            while (iterator.hasNext()) {
                menuItem = (MenuComponent) iterator.next();
                if (menuItem.isVegetable()) {
                    menuItem.print();
                }
            }

        }

    }
}

在此次的Waitress 类咱们添加的是MenuComponent ,假如MenuComponent 是MenuItem则,print会生效,在获取它的迭代器经过ComposeIterator 里面的判断逻辑hasNext()中会经过Stack pop掉,假如是SubMenu,则二者都会生效,这样就成功的将不管是子菜单仍是菜单均可以打印出来。

下面来测试下:

public class MainTest {
    public static void main(String[] args) {
        Waitress mWaitress = new Waitress();
        CakeHouseMenu mCakeHouseMenu = new CakeHouseMenu();
        DinerMenu mDinerMenu = new DinerMenu();
        mWaitress.addComponent(mCakeHouseMenu);
        mWaitress.addComponent(mDinerMenu);
        mWaitress.printMenu();;
    }
}

这里写图片描述

固然Waitress 类还提供了printVegetableMenu方法,若是此MenuComponent 是蔬菜,则会打印。读者能够本身试试效果

最后总结下就是
组合模式:将对象聚合成树形结构来表现“总体/部分”的层次结构,
组合模式能让客户以一致 的形式处理对象或者对象组合
也就是咱们能够忽略对象组合与个体对象的差异


—————————————————————————————————————————————

十3、状态模式

项目需求:糖果机项目,投硬币,退回硬币,转动转盘,糖果落下,假如糖果数量小于0了,还须要售罄状态。下面看代码:

public class CandyMachine {

    final static int SoldOutState = 0;
    final static int OnReadyState = 1;
    final static int HasCoin = 2;
    final static int SoldState = 3;

    private int state = SoldOutState;
    private int count = 0;

    public CandyMachine(int count) {
        this.count = count;
        if (count > 0) {
            state = OnReadyState;
        }
    }

    public void insertCoin() {
        switch (state) {
        case SoldOutState:
            System.out.println("you can't insert coin,the machine sold out!");
            break;
        case OnReadyState:
            state = HasCoin;
            System.out
                    .println("you have inserted a coin,next,please turn crank!");
            break;
        case HasCoin:
            System.out.println("you can't insert another coin!");

            break;
        case SoldState:
            System.out.println("please wait!we are giving you a candy!");

            break;
        }

    }

    public void returnCoin() {
        switch (state) {
        case SoldOutState:
            System.out
                    .println("you can't return,you haven't inserted a coin yet!");
            break;
        case OnReadyState:
            System.out.println("you haven't inserted a coin yet!");
            break;
        case HasCoin:

            System.out.println("coin return!");
            state = OnReadyState;

            break;
        case SoldState:
            System.out.println("sorry,you already have turned the crank!");

            break;
        }

    }

    public void turnCrank() {
        switch (state) {
        case SoldOutState:
            System.out.println("you turned,but there are no candies!");
            break;
        case OnReadyState:
            System.out.println("you turned,but you haven't inserted a coin!");
            break;
        case HasCoin:
            System.out.println("crank turn...!");
            state = SoldState;
            dispense();
            break;
        case SoldState:
            System.out
                    .println("we are giving you a candy,turning another get nothing,!");
            break;
        }

    }

    private void dispense() {
        count = count - 1;
        System.out.println("a candy rolling out!");
        if (count > 0) {
            state = OnReadyState;
        } else {
            System.out.println("Oo,out of candies");
            state = SoldOutState;
        }

    }

    public void printstate() {

        switch (state) {
        case SoldOutState:
            System.out.println("***SoldOutState***");
            break;
        case OnReadyState:
            System.out.println("***OnReadyState***");
            break;
        case HasCoin:

            System.out.println("***HasCoin***");

            break;
        case SoldState:
            System.out.println("***SoldState***");
            break;
        }

    }
}

每一个步骤封装成一个方法,每一个步骤且都有4个状态的改变。并使用printstate打印状态。

下面来测试下:

public class MainTest {
    public static void main(String[] args) {
        CandyMachine mCandyMachine=new CandyMachine(2);

        mCandyMachine.printstate();

        mCandyMachine.insertCoin();
        mCandyMachine.printstate();

        mCandyMachine.turnCrank();

        mCandyMachine.printstate();

        mCandyMachine.insertCoin();
        mCandyMachine.printstate();

        mCandyMachine.turnCrank();

        mCandyMachine.printstate();
    }
}

这里写图片描述

如今加入游戏元素:在转动转盘过程当中有%10的几率拿到2粒糖果

假如咱们如今原始的基础上修改,须要在turnCrank()与dispense()步骤中加入赢家状态,并作相应的处理。
可是咱们知道咱们在设计代码的时候必定要遵照开闭原则,对于扩展是开放的,修改是关闭的。

咱们如今来分析不变与变化的部分:变化的部分显然意见是状态,不变的是步骤,
这里写图片描述
每一个状态均可能会促发这4个动做,因此咱们获得下图:
这里写图片描述
将变化的状态封装成类,每一个类促发这4个步骤,在糖果机类则定义状态,经过不一样的状态去执行不一样状态中的行为

状态模式:能根据内部状态的变化,改变对象的行为,看起来好像修改了类

下面看代码:

public interface State {
    public void insertCoin();
    public void returnCoin();
    public void turnCrank();
    public void dispense();
    public void printstate();
}
public class OnReadyState implements State {
    private CandyMachine mCandyMachine;
    public OnReadyState(CandyMachine mCandyMachine)
    {
        this.mCandyMachine=mCandyMachine;
    }

    @Override
    public void insertCoin() {
        // TODO Auto-generated method stub
        System.out
        .println("you have inserted a coin,next,please turn crank!");
        mCandyMachine.setState(mCandyMachine.mHasCoin);
    }

    @Override
    public void returnCoin() {
        // TODO Auto-generated method stub
        System.out.println("you haven't inserted a coin yet!");

    }

    @Override
    public void turnCrank() {
        // TODO Auto-generated method stub
        System.out.println("you turned,but you haven't inserted a coin!");

    }

    @Override
    public void dispense() {
        // TODO Auto-generated method stub

    }

    @Override
    public void printstate() {
        // TODO Auto-generated method stub
        System.out.println("***OnReadyState***");

    }

}
public class HasCoin implements State {
    private CandyMachine mCandyMachine;

    public HasCoin(CandyMachine mCandyMachine) {
        this.mCandyMachine = mCandyMachine;
    }

    @Override
    public void insertCoin() {
        // TODO Auto-generated method stub
        System.out.println("you can't insert another coin!");

    }

    @Override
    public void returnCoin() {
        // TODO Auto-generated method stub
        System.out.println("coin return!");
        mCandyMachine.setState(mCandyMachine.mOnReadyState);
    }

    @Override
    public void turnCrank() {
        // TODO Auto-generated method stub
        System.out.println("crank turn...!");
        Random ranwinner=new Random();
        int winner=ranwinner.nextInt(10);
        if(winner==0)
        {
            mCandyMachine.setState(mCandyMachine.mWinnerState);

        }else
        {
            mCandyMachine.setState(mCandyMachine.mSoldState);

        }

    }

    @Override
    public void dispense() {
    }

    @Override
    public void printstate() {
        // TODO Auto-generated method stub
        System.out.println("***HasCoin***");

    }

}
public class SoldState implements State {
    private CandyMachine mCandyMachine;
    public SoldState(CandyMachine mCandyMachine)
    {
        this.mCandyMachine=mCandyMachine;
    }

    @Override
    public void insertCoin() {
        // TODO Auto-generated method stub
        System.out.println("please wait!we are giving you a candy!");

    }

    @Override
    public void returnCoin() {
        // TODO Auto-generated method stub
        System.out.println("you haven't inserted a coin yet!");

    }

    @Override
    public void turnCrank() {
        // TODO Auto-generated method stub
        System.out
        .println("we are giving you a candy,turning another get nothing,!");

    }

    @Override
    public void dispense() {
        // TODO Auto-generated method stub

        mCandyMachine.releaseCandy();
        if (mCandyMachine.getCount() > 0) {
            mCandyMachine.setState(mCandyMachine.mOnReadyState);
        } else {
            System.out.println("Oo,out of candies");
            mCandyMachine.setState(mCandyMachine.mSoldOutState);
        }



    }

    @Override
    public void printstate() {
        // TODO Auto-generated method stub
        System.out.println("***SoldState***");

    }

}
public class WinnerState implements State {

    private CandyMachine mCandyMachine;

    public WinnerState(CandyMachine mCandyMachine) {
        this.mCandyMachine = mCandyMachine;
    }

    @Override
    public void insertCoin() {
        // TODO Auto-generated method stub
        System.out.println("please wait!we are giving you a candy!");

    }

    @Override
    public void returnCoin() {
        // TODO Auto-generated method stub
        System.out.println("you haven't inserted a coin yet!");

    }

    @Override
    public void turnCrank() {
        // TODO Auto-generated method stub
        System.out
                .println("we are giving you a candy,turning another get nothing,!");

    }

    @Override
    public void dispense() {
        // TODO Auto-generated method stub


        mCandyMachine.releaseCandy();
        if (mCandyMachine.getCount() == 0) {
            mCandyMachine.setState(mCandyMachine.mSoldOutState);
        } else {
            System.out.println("you are a winner!you get another candy!");
            mCandyMachine.releaseCandy();
            if (mCandyMachine.getCount() > 0) {
                mCandyMachine.setState(mCandyMachine.mOnReadyState);
            } else {
                System.out.println("Oo,out of candies");
                mCandyMachine.setState(mCandyMachine.mSoldOutState);
            }
        }

    }

    @Override
    public void printstate() {
        // TODO Auto-generated method stub
        System.out.println("***WinnerState***");

    }

}
public class SoldOutState implements State {

    private CandyMachine mCandyMachine;
    public SoldOutState(CandyMachine mCandyMachine)
    {
        this.mCandyMachine=mCandyMachine;
    }

    @Override
    public void insertCoin() {
        // TODO Auto-generated method stub
        System.out.println("you can't insert coin,the machine sold out!");

    }

    @Override
    public void returnCoin() {
        // TODO Auto-generated method stub
        System.out
        .println("you can't return,you haven't inserted a coin yet!");

    }

    @Override
    public void turnCrank() {
        // TODO Auto-generated method stub
        System.out.println("you turned,but there are no candies!");

    }

    @Override
    public void dispense() {
        // TODO Auto-generated method stub

    }

    @Override
    public void printstate() {
        // TODO Auto-generated method stub
        System.out.println("***SoldOutState***");

    }

}
public class CandyMachine {

    State mSoldOutState;
    State mOnReadyState;
    State mHasCoin;
    State mSoldState;
    State mWinnerState;
    private State state;
    private int count = 0;

    public CandyMachine(int count) {
        this.count = count;
        mSoldOutState = new SoldOutState(this);
        mOnReadyState = new OnReadyState(this);
        mHasCoin = new HasCoin(this);
        mSoldState = new SoldState(this);
        mWinnerState = new WinnerState(this);
        if (count > 0) {
            state = mOnReadyState;
        } else {
            state = mSoldOutState;
        }
    }

    public void setState(State state) {
        this.state = state;
    }

    public void insertCoin() {
        state.insertCoin();
    }

    public void returnCoin() {
        state.returnCoin();
    }

    public void turnCrank() {
        state.turnCrank();
        state.dispense();
    }

    void releaseCandy() {

        // TODO Auto-generated method stub
        if (count > 0) {
            count = count - 1;
            System.out.println("a candy rolling out!");
        }

    }

    public int getCount() {
        return count;
    }

    public void printstate() {
        state.printstate();
    }
}

代码分析:将每一个状态单独抽取成类,加入新的状态只须要抽成类,实现对应的行为,糖果机的动做行为无需修改,这就作到了开闭原则。

下面来测试下:

public class MainTest {
    public static void main(String[] args) {
        CandyMachine mCandyMachine = new CandyMachine(6);

        mCandyMachine.printstate();

        mCandyMachine.insertCoin();
        mCandyMachine.printstate();

        mCandyMachine.turnCrank();

        mCandyMachine.printstate();

        mCandyMachine.insertCoin();
        mCandyMachine.printstate();

        mCandyMachine.turnCrank();

        mCandyMachine.printstate();
    }
}

这里写图片描述

测试代码和以前的并没有太大差异固然若是运气好就可能有2粒糖果掉落的机会。

以前的策略模式中,鸭子项目中,咱们将鸭子相同动做的不一样行为抽取出来,咱们这里也是将相同动做下的不一样状态抽取出来,因此策略模式通常状况下能够做为状态模式的基础,可是在状态模式中,状态的改变会改变更做,而策略模式总的行为固定,动做不会改变了。在模板模式中,例如咱们的泡茶,通过烧水,酝酿,倒入杯子,加入佐料,通过4个步骤,而咱们的糖果机项目彷佛也是通过几个步骤完成的,可是模板模式中的步骤是固定的,而状态模式中会随着状态改变去改变步骤。


—————————————————————————————————————————————

十4、代理模式

在上一个项目中老板要在各地都放置,因此想要监控各个糖果机,若是是在本地能够拿到糖果机对象:

public interface State{
    public void insertCoin();
    public void returnCoin();
    public void turnCrank();
    public void dispense();
    public void printstate();
    public String getstatename();
}
public class SoldState implements State {
    private CandyMachine mCandyMachine;
    public SoldState(CandyMachine mCandyMachine)
    {
        this.mCandyMachine=mCandyMachine;
    }

    @Override
    public void insertCoin() {
        // TODO Auto-generated method stub
        System.out.println("please wait!we are giving you a candy!");

    }

    @Override
    public void returnCoin() {
        // TODO Auto-generated method stub
        System.out.println("you haven't inserted a coin yet!");

    }

    @Override
    public void turnCrank() {
        // TODO Auto-generated method stub
        System.out
        .println("we are giving you a candy,turning another get nothing,!");

    }

    @Override
    public void dispense() {
        // TODO Auto-generated method stub

        mCandyMachine.releaseCandy();
        if (mCandyMachine.getCount() > 0) {
            mCandyMachine.setState(mCandyMachine.mOnReadyState);
        } else {
            System.out.println("Oo,out of candies");
            mCandyMachine.setState(mCandyMachine.mSoldOutState);
        }



    }

    @Override
    public void printstate() {
        // TODO Auto-generated method stub
        System.out.println("***SoldState***");

    }
    @Override
    public String getstatename() {
        // TODO Auto-generated method stub
        return "SoldState";
    }
}
public class CandyMachine {

    State mSoldOutState;
    State mOnReadyState;
    State mHasCoin;
    State mSoldState;
    State mWinnerState;
    private String location="";
    private State state;
    private int count = 0;

    public CandyMachine(String location,int count){
        this.location=location;
        this.count = count;
        mSoldOutState = new SoldOutState(this);
        mOnReadyState = new OnReadyState(this);
        mHasCoin = new HasCoin(this);
        mSoldState = new SoldState(this);
        mWinnerState = new WinnerState(this);
        if (count > 0) {
            state = mOnReadyState;
        } else {
            state = mSoldOutState;
        }
    }
    public String getLocation()
    {
        return location;
    }
    public void setState(State state) {
        this.state = state;
    }

    public void insertCoin() {
        state.insertCoin();
    }

    public void returnCoin() {
        state.returnCoin();
    }

    public void turnCrank() {
        state.turnCrank();
        state.dispense();
    }

    void releaseCandy() {

        // TODO Auto-generated method stub
        if (count > 0) {
            count = count - 1;
            System.out.println("a candy rolling out!");
        }

    }

    public int getCount() {
        return count;
    }

    public void printstate() {
        state.printstate();
    }
    public State getstate() {
        return state;
    }
}

以前的代码不变,在糖果机类中咱们增长一个loc位置参数,并在State中增长一个获取状态的接口

public class Monitor {
    private ArrayList<CandyMachine> candyMachinelst;

    public Monitor() {
        candyMachinelst = new ArrayList<CandyMachine>();
    }

    public void addMachine(CandyMachine mCandyMachine) {
        candyMachinelst.add(mCandyMachine);
    }

    public void report() {
        CandyMachine mCandyMachine;
        for (int i = 0, len = candyMachinelst.size(); i < len; i++) {
            mCandyMachine = candyMachinelst.get(i);
            System.out.println("Machine Loc:" + mCandyMachine.getLocation());
            System.out.println("Machine Candy count:"
                    + mCandyMachine.getCount());
            System.out.println("Machine State:"
                    + mCandyMachine.getstate().getstatename());

        }

    }

}

经过本地拿到糖果机对象遍历糖果机对象,report各个糖果机对象的信息。

测试代码:

Monitor mMonitor=new Monitor();
        CandyMachine mCandyMachine = new CandyMachine("NY",6);
        mMonitor.addMachine(mCandyMachine);

        mCandyMachine = new CandyMachine("TK",4);
        mCandyMachine.insertCoin();
        mMonitor.addMachine(mCandyMachine);

        mCandyMachine = new CandyMachine("Bj",14);
        mCandyMachine.insertCoin(); 
        mCandyMachine.turnCrank();
        mMonitor.addMachine(mCandyMachine);

        mMonitor.report();

这里写图片描述

这里咱们是经过拿到各个地方的糖果机对象,才能获得各个糖果机对象的信息,可是通常咱们是不可能拿到的,咱们可能回想到用网络,经过网络实时传输数据到后台,经过后台去拿到糖果机对象的信息,可是咱们这里要讲解的是代理模式,因此不考虑这种方法,

java中有一种rmi机制,可以让某个java虚拟机上的对象调用另外一个Java虚拟机中的对象上的方法,经过远程代理:远程对象的本地表明,经过它可让远程对象当本地对象来调用。
远程代理经过网络和真正的远程对象沟通讯息。
代理模式:为一个对象提供一个替身,以控制对这个对象的访问
被代理的对象能够是远程对象、建立开销大的对象或须要安全控制的对象
代理模式有不少变体,都是为了控制与管理对象访问
RMI远程方法调用是计算机之间经过网络实现对象调用的一种通信机制。
使用这种机制,一台计算机上的对象能够调用另外 一台计算机上的对象来获取远
程数据。
在过去,TCP/IP通信是远程通信的主要手段,面向过程的开发。
而RPC使程序员更容易地调用远程程序,但在面对复杂的信息传讯时,RPC依然
未能很好的支持
RMI被设计成一种面向对象开发方式,容许程序员使用远程对象来实现通讯

RMI的4个步骤:
制做远程接口:接口文件
远程接口的实现:Service文件
RMI服务端注册,开启服务
RMI代理端经过RMI查询到服务端,创建联系,经过接口调用远程方法

下面看一个RMI的例子:

public interface MyRemote extends Remote{

    public String sayHello() throws RemoteException;

}
@SuppressWarnings("serial")
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{

    protected MyRemoteImpl() throws RemoteException {
        super();
        // TODO Auto-generated constructor stub
    }

    @Override
    public String sayHello() throws RemoteException {
        // TODO Auto-generated method stub
        return "Hello World!";
    }
    public static void main(String[] args) {

        try {
            MyRemote service=new MyRemoteImpl();
             LocateRegistry.createRegistry(6600);
            Naming.rebind("rmi://127.0.0.1:6600/RemoteHello", service);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println( e.toString());
        } 


    }
}
public class MyRemoteClient {
    public static void main(String[] args) {

        new MyRemoteClient().go();
    }

    public void go()
    {
        try {
            MyRemote service=(MyRemote)Naming.lookup("rmi://127.0.0.1:6600/RemoteHello");
            String s=service.sayHello();
            System.out.println(s);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
    }
}

代码分析:
首先定义出一个MyRemote 接口继承自Remote,声明出须要远程实现的方法,
而后在MyRemoteImpl 服务端类继承UnicastRemoteObject 并实现MyRemote 须要远程实现的方法,而后注册开启服务,
在MyRemoteClient 客户端寻找出对应的服务,调用远程须要实现的方法。

以前咱们说咱们拿不到糖果机对象,这个时候咱们就可使用RMI,经过创建一个远程代理对象实现远程监控,下面看代码:

public interface CandyMachineRemote extends Remote{
    public String  getLocation() throws RemoteException;
    public int getCount() throws RemoteException;
    public State getstate() throws RemoteException;
}
public class CandyMachine extends UnicastRemoteObject implements CandyMachineRemote{

    State mSoldOutState;
    State mOnReadyState;
    State mHasCoin;
    State mSoldState;
    State mWinnerState;
    private String location="";
    private State state;
    private int count = 0;

    public CandyMachine(String location,int count) throws RemoteException{
        this.location=location;
        this.count = count;
        mSoldOutState = new SoldOutState(this);
        mOnReadyState = new OnReadyState(this);
        mHasCoin = new HasCoin(this);
        mSoldState = new SoldState(this);
        mWinnerState = new WinnerState(this);
        if (count > 0) {
            state = mOnReadyState;
        } else {
            state = mSoldOutState;
        }
    }
    public String getLocation()
    {
        return location;
    }
    public void setState(State state) {
        this.state = state;
    }

    public void insertCoin() {
        state.insertCoin();
    }

    public void returnCoin() {
        state.returnCoin();
    }

    public void turnCrank() {
        state.turnCrank();
        state.dispense();
    }

    void releaseCandy() {

        // TODO Auto-generated method stub
        if (count > 0) {
            count = count - 1;
            System.out.println("a candy rolling out!");
        }

    }

    public int getCount() {
        return count;
    }

    public void printstate() {
        state.printstate();
    }
    public State getstate() {
        return state;
    }

}
public interface State extends Serializable{
    public void insertCoin();
    public void returnCoin();
    public void turnCrank();
    public void dispense();
    public void printstate();
    public String getstatename();
}
public class RemoteMainTest {
    public static void main(String[] args) {

        try {
            CandyMachine service = new CandyMachine("test1", 7);
             LocateRegistry.createRegistry(6602);
            Naming.rebind("rmi://127.0.0.1:6602/test1", service);
            service.insertCoin();
            service = new CandyMachine("test2", 5);
            Naming.rebind("rmi://127.0.0.1:6602/test2", service);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(e.toString());
        }

    }
}
public class Monitor {

    private ArrayList<CandyMachineRemote> candyMachinelst;

    public Monitor() {
        candyMachinelst = new ArrayList<CandyMachineRemote>();
    }

    public void addMachine(CandyMachineRemote mCandyMachine) {
        candyMachinelst.add(mCandyMachine);
    }

    public void report() {
        CandyMachineRemote mCandyMachine;
        for (int i = 0, len = candyMachinelst.size(); i < len; i++) {
            mCandyMachine = candyMachinelst.get(i);
            try {
                System.out
                        .println("Machine Loc:" + mCandyMachine.getLocation());

                System.out.println("Machine Candy count:"
                        + mCandyMachine.getCount());
                System.out.println("Machine State:"
                        + mCandyMachine.getstate().getstatename());
            } catch (RemoteException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

}
public class MainTest {

    public static void main(String[] args) {
        Monitor mMonitor = new Monitor();

        try {
            CandyMachineRemote mCandyMachine = (CandyMachineRemote) Naming
                    .lookup("rmi://127.0.0.1:6602/test1");
            mMonitor.addMachine(mCandyMachine);
            mCandyMachine = (CandyMachineRemote) Naming
                    .lookup("rmi://127.0.0.1:6602/test2");
            mMonitor.addMachine(mCandyMachine);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        mMonitor.report();
    }
}

代码分析:远程监控糖果机,
首先也是经过定义一个须要执行方法的接口CandyMachineRemote,
糖果机继承UnicastRemoteObject 并实现CandyMachineRemote,以前咱们在本地监控器也已经也实现了,因此也这里无需添代码了。
RemoteMainTest 类做为服务类注册和开启远程代理,
MainTest 类做为客户端类寻找远程代理,
最后使用Monitor 类管理多个远程代理,也就是管理多个地点的糖果机对象。

最后看看效果吧:
这里写图片描述

动态代理:运行时动态的建立代理类,并将方法调用转发到指定类

看下代码:

public interface PersonBean {
    String getName();
    String getGender();
    String getInterests();
    int getHotOrNotRating();

    void setName(String name);
    void setGender(String gender);
    void setInterests(String interests);
    void setHotOrNotRating(int rating);
}
public class PersonBeanImpl implements PersonBean{
    String name;
    String gender;
    String interests;
    int rating;
    int ratingcount=0;
    @Override
    public String getName() {
        // TODO Auto-generated method stub
        return name;
    }

    @Override
    public String getGender() {
        // TODO Auto-generated method stub
        return gender;
    }

    @Override
    public String getInterests() {
        // TODO Auto-generated method stub
        return interests;
    }

    @Override
    public int getHotOrNotRating() {
        // TODO Auto-generated method stub
        if(ratingcount==0)      return 0;
        return (rating/ratingcount);
    }

    @Override
    public void setName(String name) {
        // TODO Auto-generated method stub
        this.name=name;
    }

    @Override
    public void setGender(String gender) {
        // TODO Auto-generated method stub
        this.gender=gender;
    }

    @Override
    public void setInterests(String interests) {
        // TODO Auto-generated method stub
        this.interests=interests;
    }

    @Override
    public void setHotOrNotRating(int rating) {
        // TODO Auto-generated method stub
        this.rating=rating;
        ratingcount++;
    }

}
public class NonOwnerInvocationHandler implements InvocationHandler{
    PersonBean person;
    public NonOwnerInvocationHandler(PersonBean person)
    {
        this.person=person;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // TODO Auto-generated method stub

        if(method.getName().startsWith("get"))
        {
            return method.invoke(person,args);
        }else if(method.getName().equals("setHotOrNotRating"))
        {
            return method.invoke(person,args);

        }else if(method.getName().startsWith("set"))
        {
            return new IllegalAccessException();
        }

        return null;
    }

}
public class OwnerInvocationHandler implements InvocationHandler{
    PersonBean person;
    public OwnerInvocationHandler(PersonBean person)
    {
        this.person=person;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // TODO Auto-generated method stub

        if(method.getName().startsWith("get"))
        {
            return method.invoke(person,args);
        }else if(method.getName().equals("setHotOrNotRating"))
        {
            return new IllegalAccessException();
        }else if(method.getName().startsWith("set"))
        {
            return method.invoke(person,args);
        }

        return null;
    }

}
public class MatchService {
    public MatchService() {

        PersonBean joe = getPersonInfo("joe", "male", "running");

        PersonBean OwnerProxy = getOwnerProxy(joe);

        System.out.println("Name is " + OwnerProxy.getName());
        System.out.println("Interests is " + OwnerProxy.getInterests());

        OwnerProxy.setInterests("Bowling");
        System.out.println("Interests are " + OwnerProxy.getInterests());
        OwnerProxy.setHotOrNotRating(50);
        System.out.println("Rating is " + OwnerProxy.getHotOrNotRating());
        OwnerProxy.setHotOrNotRating(40);
        System.out.println("Rating is " + OwnerProxy.getHotOrNotRating());

        System.out.println("**************");

        PersonBean nonOwnerProxy = getNonOwnerProxy(joe);
        System.out.println("Name is " + nonOwnerProxy.getName());
        System.out.println("Interests are " + nonOwnerProxy.getInterests());
        nonOwnerProxy.setInterests("haha");
        System.out.println("Interests are " + nonOwnerProxy.getInterests());
        nonOwnerProxy.setHotOrNotRating(60);
        System.out.println("Rating is " + nonOwnerProxy.getHotOrNotRating());

    }

    PersonBean getPersonInfo(String name, String gender, String interests) {
        PersonBean person = new PersonBeanImpl();
        person.setName(name);
        person.setGender(gender);
        person.setInterests(interests);
        return person;
    }

    PersonBean getOwnerProxy(PersonBean person) {
        return (PersonBean) Proxy.newProxyInstance(person.getClass()
                .getClassLoader(), person.getClass().getInterfaces(),
                new OwnerInvocationHandler(person));
    }

    PersonBean getNonOwnerProxy(PersonBean person) {
        return (PersonBean) Proxy.newProxyInstance(person.getClass()
                .getClassLoader(), person.getClass().getInterfaces(),
                new NonOwnerInvocationHandler(person));
    }
}
public class MainTest {


    public static void main(String[] args) {

        MatchService mMatchService=new MatchService();
    }


}


—————————————————————————————————————————————

十5、复合模式

模式常一块儿使用,组合在一个设计解决方案中
复合模式在一个解决方案中结合两个或多个模式
能解决通常性或一系列的问题
某些模式结合使用,并不就是复合模式

MVC复合模式:
MVC:Model、View、Controller
Model:是程序主体,表明了业务数据和业
务逻辑
View:是与用户交互的界面,显示数据、接收输入,但不参与实际业务逻辑
Controller:接收用户输入,并解析反馈给Model

MVC里的模式:
Model与View和Controller是观察者
模式
View以组合模式管理控件
View与Controller是策略模式关系,
Controller提供策略

音乐播放器中的MVC:
这里写图片描述

View显示试图,用户点击View的试图,经过Controller中的Button事件反馈给Model,由Model去执行具体的逻辑和并更新数据


—————————————————————————————————————————————

十6、桥接模式

项目需求:遥控器项目,每一个厂家的电视对应本身的遥控器。遥控器有打开,关闭,设置频道,设置音量。

使用传统的去设计:

public interface Control {

    public void On();
    public void Off();
    public void setChannel(int ch);
    public void setVolume(int vol);

}
public class LGControl implements Control {

    @Override
    public void On() {
        // TODO Auto-generated method stub
        System.out.println("**Open LG TV**");
    }

    @Override
    public void Off() {
        // TODO Auto-generated method stub
        System.out.println("**Off LG TV**");
    }

    @Override
    public void setChannel(int ch) {
        // TODO Auto-generated method stub
        System.out.println("**The LG TV Channel is setted "+ch+"**");
    }

    @Override
    public void setVolume(int vol) {
        // TODO Auto-generated method stub
        System.out.println("**The LG TV Volume is setted "+vol+"**");
    }

}
public class SonyControl implements Control {

    @Override
    public void On() {
        // TODO Auto-generated method stub
        System.out.println("*Open Sony TV*");
    }

    @Override
    public void Off() {
        // TODO Auto-generated method stub
        System.out.println("*Off Sony TV*");
    }

    @Override
    public void setChannel(int ch) {
        // TODO Auto-generated method stub
        System.out.println("*The Sony TV Channel is setted "+ch+"*");
    }

    @Override
    public void setVolume(int vol) {
        // TODO Auto-generated method stub
        System.out.println("*The Sony TV Volume is setted "+vol+"*");
    }

}
public interface TvControl {
    public void Onoff();
    public void  nextChannel();
    public void  preChannel();
}
public class LGTvControl extends LGControl implements TvControl{
    private static int ch=0;
    private static boolean ison=false;
    public void Onoff()
    {
        if(ison)
        {
            ison=false;
            super.Off();
        }else{
            ison=true;
            super.On();
        }
    }
    public void nextChannel()
    {
        ch++;
        super.setChannel(ch);
    }
    public void preChannel()
    {
        ch--;
        if(ch<0)
        {
            ch=200;
        }
        super.setChannel(ch);
    }

}

代码分析:在底层使用Control 接口供各个厂商具体使用,在TvControl 中使用Control 接口方法供各个厂商实现具体行为。

测试代码:

public class MainTest {
    public static void main(String[] args) {
        LGTvControl mLGTvControl=new LGTvControl();
        SonyTvControl mSonyTvControl=new SonyTvControl();

        mLGTvControl.Onoff();
        mLGTvControl.nextChannel();
        mLGTvControl.nextChannel();
        mLGTvControl.preChannel();
        mLGTvControl.Onoff();

        mSonyTvControl.Onoff();
        mSonyTvControl.preChannel();
        mSonyTvControl.preChannel();
        mSonyTvControl.preChannel();
        mSonyTvControl.Onoff();
    }


}

如今有了新需求:新的厂商须要在原先基础上增长新的供能,而且须要生产与该厂商对应的遥控器。

分析变化与不变:变化的是厂商须要增长新的功能,以及各个厂商对应各自的遥控器,各个遥控器的具体行为,不变的是各个遥控器具备的操做是相同的,厂商须要的功能中的操做是相同的,好的根据这个,咱们来写代码:

public abstract class TvControlabs {

      Control mControl=null;
    public TvControlabs(Control mControl)
    {
        this.mControl=mControl;
    }

    public abstract void Onoff();
    public abstract void nextChannel();
    public abstract void preChannel();


}

将厂商的操做抽象,以供新的厂商能够增长新的操做,而且经过传入Control 封装相应的操做,各个遥控器的操做是不变的,具体变得是操做的具体行为。

public class TvControl extends TvControlabs {
    private  int ch=0;
    private  boolean ison=false;

    public TvControl(Control mControl)
    {
        super(mControl);
    }
    @Override
    public void Onoff() {
        // TODO Auto-generated method stub

        if(ison)
        {
            ison=false;
            mControl.Off();
        }else{
            ison=true;
            mControl.On();
        }

    }

    @Override
    public void nextChannel() {
        // TODO Auto-generated method stub

        ch++;
        mControl.setChannel(ch);

    }

    @Override
    public void preChannel() {
        // TODO Auto-generated method stub

        ch--;
        if(ch<0)
        {
            ch=200;
        }
        mControl.setChannel(ch);

    }

}

TvControl 各个厂商只须要知道你传入的是什么遥控器来知道你是什么厂商

加入新的遥控器:

ublic class SharpControl implements Control {

    @Override
    public void On() {
        // TODO Auto-generated method stub
        System.out.println("***Open Sharp TV***");
    }

    @Override
    public void Off() {
        // TODO Auto-generated method stub
        System.out.println("***Off Sharp TV***");
    }

    @Override
    public void setChannel(int ch) {
        // TODO Auto-generated method stub
        System.out.println("***The Sharp TV Channel is setted "+ch+"***");
    }

    @Override
    public void setVolume(int vol) {
        // TODO Auto-generated method stub
        System.out.println("***The Sharp TV Volume is setted "+vol+"***");
    }

}

遥控器的操做是相同的,变化的是具体的行为

加入新的厂商,并加入新功能:

public class newTvControl extends TvControlabs {
    private  int ch=0;
    private  boolean ison=false;
    private int prech=0;
    public newTvControl(Control mControl) {
        super(mControl);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void Onoff() {
        // TODO Auto-generated method stub

        if(ison)
        {
            ison=false;
            mControl.Off();
        }else{
            ison=true;
            mControl.On();
        }

    }

    @Override
    public void nextChannel() {
        // TODO Auto-generated method stub
        prech=ch;
        ch++;
        mControl.setChannel(ch);

    }

    @Override
    public void preChannel() {
        // TODO Auto-generated method stub
        prech=ch;
        ch--;
        if(ch<0)
        {
            ch=200;
        }
        mControl.setChannel(ch);

    }


    public void  setChannel(int nch)
    {
        prech=ch;
        ch=nch;
        mControl.setChannel(ch);

    }
    public void   Back()
    {
        mControl.setChannel(prech);
    }
}

经过继承自抽象的 TvControlabs 加入新的功能。

桥接模式:将实现与抽象放在两个不一样的类层次中,使两个层次能够独立改变

在咱们这个项目中各个厂商TvControlabs 是抽象的,而各个遥控器Control 须要具体实现,这就是桥接模式

系统有多维角度分类时,而每一种分类又有可能变化,考虑使用桥接模式
桥接的目的是分离抽象与实现,使抽象和实现能够独立变化。

桥接模式与策略模式的差别:

桥接的目的是让底层实现和上层接口能够分别演化,从而提升移植性
策略的目的是将复杂的算法封装起来,从而便于替换不一样的算法
桥接模式是每每是为了利用已有的方法或类
策略模式是为了扩展和修改,并提供动态配置
桥接模式强调接口对象仅提供基本操做
策略模式强调接口对象提供的是一种算法


—————————————————————————————————————————————

十7、生成器模式

生成器的英文是builder,也能够称为建造者
项目需求:度假计划生成项目
思考:一个完整的度假计划包括天天的度假状况,度假的日期,度假的天数,而其中天天的度假状况又可能包括度假住的酒店,度假的事件,度假的日期,度假的门票等,而在一个完整的度假计划中,度假的天数,日期,天天度假的状况又是变化的。
分析上面咱们知道上面是一个对象包含另外一个对象,另外一个对象又包含另外一个对象
这里写图片描述
上图是一个完整的度假计划对象包括几个度假天数对象
这里写图片描述
而上图中是由许多个不一样的完整计划包括一个完整的度假计划,一个完整的度假计划对象包括几个度假天数对象

生成器模式:封装一个复杂对象构造过程,并容许按步骤构造。
这里写图片描述
上图就是一个标准的生成器执行过程,下面看代码:

public class VacationDay {
    private Date mDate;
    private String mHotels;
    private ArrayList<String> mTickets = null;
    private ArrayList<String> mEvents = null;

    public VacationDay(Date date) {
        mDate = date;
        mTickets = new ArrayList<String>();
        mEvents = new ArrayList<String>();
    }

    public void setDate(Date date) {
        mDate = date;
    }

    public void setHotel(String mHotels) {
        this.mHotels = mHotels;
    }

    public void addTicket(String ticket) {
        mTickets.add(ticket);
    }

    public void addEvent(String event) {
        mEvents.add(event);
    }

    public String showInfo() {
        StringBuilder stb = new StringBuilder();
        stb.append("Date:" + mDate.toString() + "\n");
        stb.append("Hotel:" + mHotels + "\n");
        stb.append("Tickets:" + mTickets.toString() + "\n");
        stb.append("Events" + mEvents.toString() + "\n");

        return stb.toString();
    }
}

这是最基层的对象:天天的度假状况对象,包括这一天的度假日期,住的酒店,门票,发生的事件。

public class Vacation {
    private ArrayList<VacationDay> mVacationDayLst;
    private Date mStDate;
    private int mDays = 0;
    private VacationDay mVacationDay;

    public Vacation(String std) {
        mVacationDayLst = new ArrayList<VacationDay>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            mStDate = sdf.parse(std);
            mVacationDay = new VacationDay(mStDate);
            mVacationDayLst.add(mVacationDay);
            mDays++;
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void addDay() {

        mVacationDay = new VacationDay(nextDate(mDays));
        mVacationDayLst.add(mVacationDay);
        mDays++;
    }


    public void setHotel(String mHotels) {
        mVacationDay.setHotel(mHotels);
    }

    public void addTicket(String ticket) {
        mVacationDay.addTicket(ticket);
    }

    public void addEvent(String event) {
        mVacationDay.addEvent(event);
    }

    public void showInfo() {
        for (int i = 0, len = mVacationDayLst.size(); i < len; i++) {
            System.out.println("** " + (i + 1) + " day**");
            System.out.println(mVacationDayLst.get(i).showInfo());

        }
    }

    private Date nextDate(int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(mStDate);
        cal.add(Calendar.DATE, n);
        return cal.getTime();
    }
}

这是位于中间位置的对象:完整度假计划对象,包括度假天数,度假的日期,天天度假状况对象

public abstract class AbsBuilder {

    public Vacation mVacation;

    public AbsBuilder(String std) {
        mVacation = new Vacation(std);
    }

    public abstract void buildvacation();

    public abstract void addHotel(String hotel);

    public abstract void addTicket(String ticket);

    public abstract void addEvent(String tvent);

    public Vacation getVacation() {

        return mVacation;

    }

}

由于一个完整的度假计划,可能有3天的,4天的,因此将它抽象出来,暴露出一个完整的度假计划对象

public class Builder3d extends AbsBuilder {

    public Builder3d(String std) {
        super(std);
        // TODO Auto-generated constructor stub

    }

    @Override
    public void addHotel(String hotel) {
        // TODO Auto-generated method stub
        mVacation.setHotel(hotel);
    }

    @Override
    public void addTicket(String ticket) {
        // TODO Auto-generated method stub
        mVacation.addTicket(ticket);
    }

    @Override
    public void addEvent(String event) {
        // TODO Auto-generated method stub
        mVacation.addEvent(event);
    }

    @Override
    public void buildvacation() {
        // TODO Auto-generated method stub
        addTicket("Plane Ticket");
        addEvent("Fly to Destination");
        addEvent("Supper");
        addEvent("Dancing");
        addHotel("Four Seasons");

        mVacation.addDay();
        addTicket("Theme Park");
        addEvent("Bus to Park");
        addEvent("lunch");
        addHotel("Four Seasons");

        mVacation.addDay();

        addTicket("Plane Ticket");
        addEvent("City Tour");
        addEvent("Fly to Home");

    }

}
public class Builder4d extends AbsBuilder {

    public Builder4d(String std) {
        super(std);
        // TODO Auto-generated constructor stub

    }


    @Override
    public void addHotel(String hotel) {
        // TODO Auto-generated method stub
        mVacation.setHotel(hotel);
    }

    @Override
    public void addTicket(String ticket) {
        // TODO Auto-generated method stub
        mVacation.addTicket(ticket);
    }

    @Override
    public void addEvent(String event) {
        // TODO Auto-generated method stub
        mVacation.addEvent(event);
    }

    @Override
    public void buildvacation() {
        // TODO Auto-generated method stub
        addTicket("Plane Ticket");
        addEvent("Fly to Destination");
        addEvent("Supper");
        addHotel("Hilton");

        mVacation.addDay();
        addTicket("Zoo Ticket");
        addEvent("Bus to Zoo");
        addEvent("Feed animals");
        addHotel("Hilton");

        mVacation.addDay();
        addTicket("Beach");
        addEvent("Swimming");
        addHotel("Home inn");

        mVacation.addDay();
        addTicket("Plane Ticket");
        addEvent("Fly to Home");
    }

}
public class Director {
    private AbsBuilder builder;

    public Director(AbsBuilder builder)
    {
        this.builder=builder;
    }
    public void setBuilder(AbsBuilder builder)
    {
        this.builder=builder;
    }
    public void construct()
    {
        builder.buildvacation();
        builder.getVacation().showInfo();
    }
}

Builder3d ,Builder4d 对象继承AbsBuilder,使用暴露的完整计划对象执行相应的操做,使用buildvacation()去封装某个完整的计划详情,再使用Director 类封装AbsBuilder ,经过construct()方法使一个完整的AbsBuilder 构建出来。

经过一层层的封装将一个复杂的对象过程简单化。

下面来测试下:

public class MainTest {

    public static void main(String[] args) {

        Director mDirector = new Director(new Builder4d("2017-12-29"));

        mDirector.construct();

        mDirector.setBuilder(new Builder3d("2017-8-30"));
        mDirector.construct();
    }

能够看到外面能够很便捷的使用。

在上面咱们假设须要DIY,或者只有一个完整的度假计划,咱们则能够省略抽象的生成器AbsBuilder 以及 指导者类Director 。看下面的代码:

public class BuilderSelf {
    public Vacation mVacation;

    public BuilderSelf(String std) {
        mVacation = new Vacation(std);
        // TODO Auto-generated constructor stub

    }

    public BuilderSelf addDay() {
        // TODO Auto-generated method stub

        mVacation.addDay();
        return this;
    }

    public BuilderSelf addHotel(String hotel) {
        // TODO Auto-generated method stub
        mVacation.setHotel(hotel);
        return this;
    }

    public BuilderSelf addTicket(String ticket) {
        // TODO Auto-generated method stub
        mVacation.addTicket(ticket);
        return this;
    }

    public BuilderSelf addEvent(String event) {
        // TODO Auto-generated method stub
        mVacation.addEvent(event);
        return this;
    }

    public Vacation getVacation() {

        return mVacation;

    }
}

测试代码:

public static void testself() {
        BuilderSelf builder = new BuilderSelf("2017-9-29");

        builder.addTicket("Plane Ticket").addEvent("Fly to Destination")
                .addEvent("Supper").addHotel("Hilton");

        builder.addDay().addTicket("Zoo Ticket").addEvent("Bus to Zoo")
                .addEvent("Feed animals").addHotel("Home Inn");

        builder.addDay();
        builder.addTicket("Beach");
        builder.addEvent("Swimming");
        builder.addHotel("Home inn");

        builder.addDay().addTicket("Plane Ticket").addEvent("Fly to Home");
        builder.getVacation().showInfo();
    }

每次执行相应的返回都会返回对象自己,因此咱们能够连续.的形式去调用。

由此咱们联想到java中的StringBuilder也是经过生成器模式设计的。还有andorid的通知等等….

在咱们以前学习过的工厂模式也是建立对象,
生成器模式:封装一个复杂对象构造过程,并容许按步骤构造。
优势:
将复杂对象的建立过程封装起来
容许对象经过几个步骤来建立,而且能够改变过程(工厂模式只有一个步骤)
只需指定具体生成器就能生成特定对象,隐藏类的内部结构
对象的实现能够被替换

生成器模式和抽象工厂模式在功能上很类似,主要区别:
生成器通常用来建立大的复杂的对象
生成器模式强调的是一步步建立对象,能够改变步骤来生成不一样的对象
通常来讲生成器模式中对象不直接返回


—————————————————————————————————————————————

十8、责任链模式

项目需求:购买请求决策项目
购买请求决策项目介绍
决策因素:价格
决策级别:组长、部长、副总、总裁

咱们创建一个Switch语句去判断价格,到底谁决策:
这里写图片描述

可是咱们又因为某一天会减小个别决策级别,使用Switch须要修改里面的代码,便于扩展,因此有了下图:
这里写图片描述
经过价格首先将决策交给某我的,若是某我的不能决策又交给下我的,造成一个链式结构,每一个Approver类中都设定一个Approver类,经过设定的Approver类而连接下一个Approver
经过ProcessRequest()方法去具体判断该Approver是否有执行权。

下图描述的是一个责任链的一个过程:

这里写图片描述

责任链模式:若是有多个对象都有机会处理请求,责任链可以使请求的发送者和接收者解耦,请求沿着责任链传递,直到有一个对象处理了它为止。

责任链模式
优势:
将请求的发送者和接收者解耦,使多个对象都有机会处理这个请求
能够简化对象,由于它无须知道链的结构
能够动态地增长或删减处理请求的链结构
缺点:
请求从链的开头进行遍历,对性能有必定的损耗
并不保证请求必定被处理

好的,下面看代码:

public class PurchaseRequest {
    private int Type = 0;
    private int Number = 0;
    private float Price = 0;
    private int ID = 0;

    public PurchaseRequest(int Type, int Number, float Price) {
        this.Type = Type;
        this.Number = Number;
        this.Price = Price;
    }

    public int GetType() {
        return Type;
    }

    public float GetSum() {
        return Number * Price;
    }

    public int GetID() {
        return (int) (Math.random() * 1000);
    }
}
public abstract class Approver {
     Approver successor;
     String Name;
    public Approver(String Name)
    {
        this.Name=Name;
    }
    public abstract void ProcessRequest( PurchaseRequest request);
    public void SetSuccessor(Approver successor) {
        // TODO Auto-generated method stub
        this.successor=successor;
    }
}
public class GroupApprover extends Approver {

    public GroupApprover(String Name) {
        super(Name+" GroupLeader");
        // TODO Auto-generated constructor stub

    }

    @Override
    public void ProcessRequest(PurchaseRequest request) {
        // TODO Auto-generated method stub

        if (request.GetSum() < 5000) {
            System.out.println("**This request " + request.GetID()
                    + " will be handled by "
                    + this.Name + " **");
        } else {
            successor.ProcessRequest(request);
        }
    }

}
public class DepartmentApprover extends Approver {

    public DepartmentApprover(String Name) {
        super(Name + " DepartmentLeader");

    }

    @Override
    public void ProcessRequest(PurchaseRequest request) {
        // TODO Auto-generated method stub

        if ((5000 <= request.GetSum()) && (request.GetSum() < 10000)) {
            System.out.println("**This request " + request.GetID()
                    + " will be handled by " + this.Name + " **");
        } else {
            successor.ProcessRequest(request);
        }

    }

}
public class PresidentApprover extends Approver {

    public PresidentApprover(String Name) {
        super(Name + " President");

    }

    @Override
    public void ProcessRequest(PurchaseRequest request) {
        // TODO Auto-generated method stub
        if (50000 <= request.GetSum()) {
            System.out.println("**This request " + request.GetID()
                    + " will be handled by " + this.Name + " **");
        }else {
            successor.ProcessRequest(request);
        }
    }

}
public class VicePresidentApprover extends Approver {

    public VicePresidentApprover(String Name) {
        super(Name + " Vice President");
    }

    @Override
    public void ProcessRequest(PurchaseRequest request) {
        // TODO Auto-generated method stub
        if ((10000 <= request.GetSum()) && (request.GetSum() < 50000)) {
            System.out.println("**This request " + request.GetID()
                    + " will be handled by " + this.Name + " **");
        } else {
            successor.ProcessRequest(request);
        }
    }

}

PurchaseRequest 类为决策请求,各个批准者经过继承抽象的Approver 实现ProcessRequest方法执行具体的判断,经过SetSuccessor可让每一个Approver 都连接上下一个Approver.

public class Client {

    public Client() {

    }

    public PurchaseRequest sendRequst(int Type, int Number, float Price) {
        return new PurchaseRequest(Type, Number, Price);
    }

}

经过这个类模拟客户端发送决策请求,下面看下测试代码:

public class MainTest {

    public static void main(String[] args) {

        Client mClient=new Client();
        Approver GroupLeader=new GroupApprover("Tom");
        Approver DepartmentLeader=new DepartmentApprover("Jerry");
        Approver VicePresident=new VicePresidentApprover("Kate");
        Approver President=new PresidentApprover("Bush");

        GroupLeader.SetSuccessor(DepartmentLeader);
        DepartmentLeader.SetSuccessor(VicePresident);
        VicePresident.SetSuccessor(President);
        President.SetSuccessor(GroupLeader);

        GroupLeader.ProcessRequest(mClient.sendRequst(1, 100, 40));
        DepartmentLeader.ProcessRequest(mClient.sendRequst(2, 200, 40));
        VicePresident.ProcessRequest(mClient.sendRequst(3, 300, 40));
        President.ProcessRequest(mClient.sendRequst(4, 400, 140));

    }


}

在测试代码中咱们首先须要将每一个Approver准备连接的下一个Approver经过SetSuccessor连接好,这样才能实现连接的效果,在咱们此测试代码中咱们循环连接,因此就算不管咱们怎么设置连接Approver,以及经过谁去ProcessRequest 获得的结果都是相同的。

学习事后你们可能会以为责任链模式和状态模式没什么差异,责任链模式经过上面的价格不一样而执行不一样的链条,而状态模式经过状态不一样执行不一样的操做

责任链模式和状态模式主要区别:
责任链模式注重请求的传递
状态模式注重对象状态的转换

责任链模式:若是有多个对象都有机会处理请求,责任链可以使请求的发送者和接收者解耦,请求沿着责任链传递,直到有一个对象处理了它为止。
适用场合:
有多个对象能够处理一个请求
不明确接收者的状况
有序、无序链,线型、树形、环形链


—————————————————————————————————————————————

十9、蝇量模式

蝇量模式:蝇表示小,细粒的,量则是大量,大量的细粒的对象。

景观设计软件项目遇到的问题:
树:XY坐标,树的大小,外观,须要不少树
10000000棵树

咱们先用最传统的设计一下:

public class Tree {
    private int xCoord, yCoord, age;

    public Tree(int xCoord, int yCoord, int age) {
        this.xCoord = xCoord;
        this.yCoord = yCoord;
        this.age = age;
    }

    public void display() {
    }
}

建立一个树对象,display()显示树的信息,但因为10000000有点多,因此这里就不现实了

public class TreesTest {

    private int length = 10000000;
    private Tree[] treelst = new Tree[length];

    public TreesTest() {
        for (int i = 0; i < length; i++) {
            treelst[i] = new Tree((int) (Math.random() * length),
                    (int) (Math.random() * length),
                    (int) (Math.random() * length) % 5);
        }
    }

    public void display() {
        for (int i = 0, len = treelst.length; i < len; i++) {
            treelst[i].display();
        }
    }

}

经过TreesTest 将10000000树对象构建出来,display遍历显示树的信息。

public class MainTest {

    public static void main(String[] args) {
        showMemInfo();
        TreesTest mTreesTest;
        mTreesTest = new TreesTest();

        showMemInfo();
        mTreesTest.display();
        showMemInfo();
    }

    public static void showMemInfo() {
        // 最大内存:
        long max = Runtime.getRuntime().maxMemory();
        // 分配内存:
        long total = Runtime.getRuntime().totalMemory();
        // 已分配内存中的剩余空间 :
        long free = Runtime.getRuntime().freeMemory();
        // 已占用的内存:
        long used = total - free;

        System.out.println("最大内存 = " + max);
        System.out.println("已分配内存 = " + total);
        System.out.println("已分配内存中的剩余空间 = " + free);
        System.out.println("已用内存 = " + used);
        System.out.println("时间 = " + System.currentTimeMillis());
        System.out.println("");

    }

}

经过showMemInfo将程序运行所占用的内存打印出,在建立1千万树对象时以前以后分别打印,在display以后打印,下面看看结果:
这里写图片描述
能够看到在建立了1千万的树对象以后已用内存明显增多了许多,时间大概也用了4秒左右,而display内存和使用并没有明显增长。

思考:这些树之间有啥关系?树与树都是树对象,只是他们须要显示的具体的坐标以及年龄有所差别也就是树的属性值,以前咱们也能够看到display内存几乎无明显增加。

public class TreeFlyWeight {

    public TreeFlyWeight() {

    }

    public void display(int xCoord, int yCoord, int age) {
        // System.out.print("x");
    }

}
public class TreeManager {

    private int length = 10000000;
    int[] xArray = new int[length], yArray = new int[length],
            AgeArray = new int[length];

    private TreeFlyWeight mTreeFlyWeight;

    public TreeManager() {

        mTreeFlyWeight = new TreeFlyWeight();
        for (int i = 0; i < length; i++) {

            xArray[i] = (int) (Math.random() * length);
            yArray[i] = (int) (Math.random() * length);
            AgeArray[i] = (int) (Math.random() * length) % 5;

        }

    }

    public void displayTrees() {

        for (int i = 0; i < length; i++) {
            mTreeFlyWeight.display(xArray[i], yArray[i], AgeArray[i]);
        }
    }

}

能够看到如今咱们只建立了一个树对象,只是在display时1千万次。

而后咱们如今看看内存:

public class MainTest {

    public static void main(String[] args) {

        showMemInfo();

        TreeManager mTreeManager;
        mTreeManager = new TreeManager();

        showMemInfo();
        mTreeManager.displayTrees();
        showMemInfo();

    }

    public static void showMemInfo() {
        // 已分配内存中的剩余空间 :
        long free = Runtime.getRuntime().freeMemory();
        // 分配内存:
        long total = Runtime.getRuntime().totalMemory();
        // 最大内存:
        long max = Runtime.getRuntime().maxMemory();
        // 已占用的内存:

        long used = total - free;

        System.out.println("最大内存 = " + max);
        System.out.println("已分配内存 = " + total);
        System.out.println("已分配内存中的剩余空间 = " + free);
        System.out.println("已用内存 = " + used);
        System.out.println("时间 = " + System.currentTimeMillis());
        System.out.println("");
    }

}

这里写图片描述
和以前的图中内存明显要少了许多。

蝇量模式:经过共享的方式高效地支持大量细粒度的对象。

下面咱们再来分析一张完整的蝇量模式图:
这里写图片描述
经过蝇量工厂中传入不一样的key类型,获得不一样的蝇量对象,蝇量对象以Operation显示蝇量的状态属性,经过ConcreteFlyweight去管理,下面咱们在生产的1千万树中也须要既有树也有草对象,看代码:

public abstract class Plant {

    public Plant() {

    }

    public abstract void display(int xCoord, int yCoord, int age);

}
public class Grass extends Plant {

    @Override
    public void display(int xCoord, int yCoord, int age) {
        // TODO Auto-generated method stub
        // System.out.print("Grass x");
    }

}
public class Tree extends Plant {

    @Override
    public void display(int xCoord, int yCoord, int age) {
        // TODO Auto-generated method stub
        // System.out.print("Tree x");
    }

}

经过抽象Plant 植物类,去构造草和树对象。

public class PlantFactory {

    private HashMap<Integer, Plant> plantMap = new HashMap<Integer, Plant>();

    public PlantFactory() {

    }

    public Plant getPlant(int type) {

        if (!plantMap.containsKey(type)) {

            switch (type) {
            case 0:
                plantMap.put(0, new Tree());
                break;
            case 1:
                plantMap.put(1, new Grass());
                break;
            }
        }

        return plantMap.get(type);
    }
}

经过PlantFactory 植物工厂传入key去获取相应的植物对象,这里传入0表示的树,1是草对象,并且经过HasHMap分别仅构造出一个植物对象

public class PlantManager {

    private int length = 10000000;
    private int[] xArray = new int[length], yArray = new int[length],
            AgeArray = new int[length], typeArray = new int[length];

    private PlantFactory mPlantFactory;
    public PlantManager() {

        mPlantFactory=new PlantFactory();
        for (int i = 0; i < length; i++) {

            xArray[i] = (int) (Math.random() * length);
            yArray[i] = (int) (Math.random() * length);
            AgeArray[i] = (int) (Math.random() * length) % 5;
            typeArray[i]= (int) (Math.random() * length) % 2;
        }
    }

    public void displayTrees() {
        for (int i = 0; i < length; i++) {
            mPlantFactory.getPlant(typeArray[i]).display(xArray[i], yArray[i], AgeArray[i]);
            }
    }
}

和以前同样仍是经过几个数组封装1千万植物的属性值,这里增长一个植物类型数组,固然其实也能够用二维数组,而后包含4个一维,可是发现二维用的内存更大,因此这里不考虑,而后仍是和以前同样经过display遍历植物的属性值。

如今来测试下:

public class MainTest {

    public static void main(String[] args) {

        showMemInfo();

        PlantManager mPlantManager;
        mPlantManager = new PlantManager();

        showMemInfo();
        mPlantManager.displayTrees();
        showMemInfo();

    }

    public static void showMemInfo() {
        // 已分配内存中的剩余空间 :
        long free = Runtime.getRuntime().freeMemory();
        // 分配内存:
        long total = Runtime.getRuntime().totalMemory();
        // 最大内存:
        long max = Runtime.getRuntime().maxMemory();
        // 已占用的内存:

        long used = total - free;

        System.out.println("最大内存 = " + max);
        System.out.println("已分配内存 = " + total);
        System.out.println("已分配内存中的剩余空间 = " + free);
        System.out.println("已用内存 = " + used);
        System.out.println("时间 = " + System.currentTimeMillis());
        System.out.println("");
    }

}

这里写图片描述

能够看到一个完整的蝇量模式能够容纳不一样的对象而且显示,并且内存相比第一个传统的也要减小很多。
这里写图片描述

优势:
减小运行时的对象实例个数,节省建立开销和内存
将许多“虚拟”对象的状态集中管理
缺点:
系统设计更加复杂
须要专门维护对象的外部状态

适用场合:
须要大量细粒度对象
这些对象的外部状态很少,也就是咱们例子中的属性。
按照内部状态分红几个组,每个组都仅用一个蝇量对象代替


—————————————————————————————————————————————

二10、解释器模式

大数据统计项目遇到的问题:
按照计算模型对现有数据统计、分析、预测
通常的计算模型是一个或多个运算公式,一般是加减乘除四则运算
计算模型须要运行期编辑
设计方案要有高扩展性

思考怎么设计
首先计算模型里有两类符号:数据和计算符
咱们计算模型的数据在数据库是固定的,是终结型,而计算模型中的计算符每每是根据咱们人为的要求在运行期编辑,也就是对数据究竟是加减乘除是变化的。
想到这里咱们考虑到用逆波兰算法分析算式语法,到底逆波兰是怎么具体分析的,能够自行百度了解,使用逆波兰分析了算法格式以后,咱们用咱们定义好的解释器处理数据,解释器就是咱们自行定义好的算法,例如这里加法,咱们须要在解释器预先定义好。

解释器模式:定义一个语法, 定义一个解释器,该解释器处理该语法句子
将某些复杂问题,表达为某种语法规则,而后构建解释器来解释处理这类句子

这里写图片描述

经过客户端传入具体的语法,经过解释器具体下发处理。

这里写图片描述
上图即是咱们例子中的项目解释器逻辑图。
经过逆波兰分析好语法格式后,经过Calculator 去让解释器去寻找对应的解释器,下面看具体代码:

public abstract class AbstractExpresstion {
    public abstract Float interpreter(HashMap<String, Float> var);
}

经过HashMap键值对简单的模仿数据库

public class VarExpresstion extends AbstractExpresstion {
    private String key;

    public VarExpresstion(String _key) {

        this.key = _key;

    }

    @Override
    public Float interpreter(HashMap<String, Float> var) {
        // TODO Auto-generated method stub
        return var.get(this.key);
    }

}

由于变量咱们只须要经过Key获得它的数据。

public abstract class SymbolExpresstion extends AbstractExpresstion {
    protected AbstractExpresstion left;
    protected AbstractExpresstion right;

    public SymbolExpresstion(AbstractExpresstion _left,
            AbstractExpresstion _right) {
        this.left = _left;

        this.right = _right;
    }

}

而计算符咱们并不知道左边的解和右边的解释各是什么。

public class AddExpresstion extends SymbolExpresstion {

    public AddExpresstion(AbstractExpresstion _left, AbstractExpresstion _right) {
        super(_left, _right);
        // TODO Auto-generated constructor stub
    }

    @Override
    public Float interpreter(HashMap<String, Float> var) {
        // TODO Auto-generated method stub
        return super.left.interpreter(var) + super.right.interpreter(var);
    }

}
public class DivExpresstion extends SymbolExpresstion {

    public DivExpresstion(AbstractExpresstion _left, AbstractExpresstion _right) {
        super(_left, _right);
        // TODO Auto-generated constructor stub
    }

    @Override
    public Float interpreter(HashMap<String, Float> var) {
        // TODO Auto-generated method stub
        return super.left.interpreter(var) / super.right.interpreter(var);
    }

}
public class MultiExpresstion extends SymbolExpresstion {

    public MultiExpresstion(AbstractExpresstion _left,
            AbstractExpresstion _right) {
        super(_left, _right);
        // TODO Auto-generated constructor stub
    }

    @Override
    public Float interpreter(HashMap<String, Float> var) {
        // TODO Auto-generated method stub
        return super.left.interpreter(var) * super.right.interpreter(var);
    }

}
public class SubExpresstion extends SymbolExpresstion {

    public SubExpresstion(AbstractExpresstion _left, AbstractExpresstion _right) {
        super(_left, _right);
        // TODO Auto-generated constructor stub
    }

    @Override
    public Float interpreter(HashMap<String, Float> var) {
        // TODO Auto-generated method stub
        return super.left.interpreter(var) - super.right.interpreter(var);
    }

}

在加减乘除解释器中经过重写interpreter()方法去计算,具体怎是经过构造函数传入的解释器具体再执行interpreter()方法,假如是var解释器,则直接获得变量,假如是其余的乘等,则须要再次进入乘的interpreter()方法,能够看出这是一个迭代的方式计算。

下面看看逆波兰分析算法:

public class RPN {

    private ArrayList<String> expression = new ArrayList<String>();// 存储中序表达式

    private ArrayList<String> right = new ArrayList<String>();// 存储右序表达式

    private AbstractExpresstion result;// 结果

    // 依据输入信息建立对象,将数值与操做符放入ArrayList中
    public RPN(String input) {
        StringTokenizer st = new StringTokenizer(input, "+-*/()", true);
        while (st.hasMoreElements()) {
            expression.add(st.nextToken());
        }
    }

    // 将中序表达式转换为右序表达式
    private void toRight() {
        Stacks aStack = new Stacks();
        String operator;
        int position = 0;
        while (true) {
            if (Calculate.isOperator((String) expression.get(position))) {
                if (aStack.top == -1
                        || ((String) expression.get(position)).equals("(")) {
                    aStack.push(expression.get(position));
                } else {
                    if (((String) expression.get(position)).equals(")")) {
                        if (!((String) aStack.top()).equals("(")) {
                            operator = (String) aStack.pop();
                            right.add(operator);
                        }
                    } else {
                        if (Calculate.priority((String) expression
                                .get(position)) <= Calculate
                                .priority((String) aStack.top())
                                && aStack.top != -1) {
                            operator = (String) aStack.pop();
                            if (!operator.equals("("))
                                right.add(operator);
                        }
                        aStack.push(expression.get(position));
                    }
                }
            } else
                right.add(expression.get(position));
            position++;
            if (position >= expression.size())
                break;
        }
        while (aStack.top != -1) {
            operator = (String) aStack.pop();
            right.add(operator);
        }
    }

    // 对右序表达式进行求值
    public void getResult(HashMap<String, Float> var) {
        this.toRight();
        Stack<AbstractExpresstion> stack = new Stack<AbstractExpresstion>();
        AbstractExpresstion op1, op2;
        String is = null;
        Iterator it = right.iterator();

        while (it.hasNext()) {
            is = (String) it.next();
            if (Calculate.isOperator(is)) {
                op2 = stack.pop();
                op1 = stack.pop();
                stack.push(Calculate.twoResult(is, op1, op2));
            } else
                stack.push(new VarExpresstion(is));
        }
        result = stack.pop();
        it = expression.iterator();
        while (it.hasNext()) {
            System.out.print((String) it.next());
        }
        System.out.println("=" + result.interpreter(var));
    }

    public static class Calculate {
        // 判断是否为操做符号
        public static boolean isOperator(String operator) {
            if (operator.equals("+") || operator.equals("-")
                    || operator.equals("*") || operator.equals("/")
                    || operator.equals("(") || operator.equals(")"))
                return true;
            else
                return false;
        }

        // 设置操做符号的优先级别
        public static int priority(String operator) {
            if (operator.equals("+") || operator.equals("-")
                    || operator.equals("("))
                return 1;
            else if (operator.equals("*") || operator.equals("/"))
                return 2;
            else
                return 0;
        }

        // 作2值之间的计算
        public static AbstractExpresstion twoResult(String op,
                AbstractExpresstion a, AbstractExpresstion b) {
            try {

                AbstractExpresstion result = null;
                if (op.equals("+"))
                    result = new AddExpresstion(a, b);
                else if (op.equals("-"))
                    result = new SubExpresstion(a, b);
                else if (op.equals("*"))
                    result = new MultiExpresstion(a, b);
                else if (op.equals("/"))
                    result = new DivExpresstion(a, b);
                else
                    ;
                return result;
            } catch (NumberFormatException e) {
                System.out.println("input has something wrong!");
                return null;
            }
        }
    }

    // 栈类
    public class Stacks {
        private LinkedList list = new LinkedList();
        int top = -1;

        public void push(Object value) {
            top++;
            list.addFirst(value);
        }

        public Object pop() {
            Object temp = list.getFirst();
            top--;
            list.removeFirst();
            return temp;

        }

        public Object top() {
            return list.getFirst();
        }
    }
}

首先在构造经过expression将分隔开来的计算模型存起来,toRight则是将右序表达式痛殴right集合存起来,getResult将结果计算出来,Calculate类则是作具体的分析,经过twoResult()去拿到具体的解释器,Stacks 类则是起到了承接的做用,将逆波兰分析的语法push,在须要的时候pop出来。

下面咱们看看具体的客户端:

public class Calculator {

    public Calculator() {
        float[][] dataSource = new float[3][6];
        System.out.println("data source:");
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 6; j++) {
                dataSource[i][j] = (float) (Math.random() * 100);
                System.out.print(dataSource[i][j] + ",");
            }
            System.out.println(";");
        }

        try {
            System.out.println("Input a expression:");
            BufferedReader is = new BufferedReader(new InputStreamReader(
                    System.in));
            for (;;) {
                String input = new String();
                input = is.readLine().trim();
                if (input.equals("q"))
                    break;
                else {
                    RPN boya = new RPN(input);
                    HashMap<String, Float> var;
                    for (int i = 0; i < 3; i++) {
                        var = new HashMap<String, Float>();
                        var.put("a", dataSource[i][0]);
                        var.put("b", dataSource[i][1]);
                        var.put("c", dataSource[i][2]);
                        var.put("d", dataSource[i][3]);
                        var.put("e", dataSource[i][4]);
                        var.put("f", dataSource[i][5]);

                        boya.getResult(var);

                    }

                }
                System.out
                        .println("Input another expression or input 'q' to quit:");
            }
            is.close();
        } catch (IOException e) {
            System.out.println("Wrong input!!!");
        }

    }

}

客户端则是简单的建立除了3组,每组6个数组的HashMap集合,经过控制台输入的计算模型,传入给逆波兰分析算法,在经过最后的getResult传给解释器处理处理。

public class MainTest {

    public static void main(String[] args) {
        new Calculator();
    }

}

测试代码只须要将客户端Calculator类new出来经过在控制台输入计算模型则会拿到相应的统计结果:
这里写图片描述

解释器模式:定义一个语法, 定义一个解释器,该解释器处理该语法句子

优势:
容易修改,修改语法规则只要修改相应非终结符便可
扩展方便,扩展语法,只要增长非终结符类便可
缺点:
对于复杂语法的表示会产生复杂的类层次结构,不便管理和维护
解释器采用递归方式,效率会受影响

注意事项:
尽可能不要在重要的模块中使用解释器模式
解释器模式在实际的系统开发中使用的很是少
能够考虑一下Expression4J、MESP、Jep等开源的解析工具包

适用场合: 当你有一个简单语法,并且效率不是问题的时候 一些数据分析工具、报表设计工具、科学计算工具等


—————————————————————————————————————————————

二11、中介者模式

智慧房屋公司的产品:
闹钟、咖啡机、电视机、窗帘等,当主人须要起床时闹钟提醒主人,主人出去后,闹钟唤醒其余电器关掉,在必定时间闹钟唤醒咖啡机煮咖啡,打开电视,过几分钟又唤醒关电视等等。

首先咱们想到这么以类图:
这里写图片描述
每一个产品之间串联唤醒,新的需求,加入一个新的产品须要修改每一个产品的唤醒结构。

思考如何设计:
各对象有几种状态改变
相互做用如何
这里写图片描述
上图经过创建一个中介者,各产品发送状态给中介者,中介者再使须要唤醒的产品改变状态。这样在须要新增产品时也就无需修改每一个产品,只须要在中介者中修改相应的状态。

中介者模式:用一个中介对象来封装一系列的对象交互。
中介者使各对象不须要显式地相互引用,从而使其耦合松散,并且能够独立地改变它们之间的交互

这里写图片描述

上图是一个完整的中介者模式类图,对于图来讲它是相对一个较大的架构设计的,它首先将中介者抽象出来了Mediator,ConcreteMediator继承自它,而在本例子中固然咱们须要一个中介者,为了之后更好的扩展我也能够像图例所示,定义出Mediator抽象类。而后图中定义了抽线的Colleague类,在Colleague中放入Mediator,而后具体的Colleague类继承自Colleague,经过传入的Mediator去处理事件。

下面看看具体的代码:

public interface Mediator {
    public abstract void Register(String colleagueName, Colleague colleague);

    public abstract void GetMessage(int stateChange, String colleagueName);
}
public class ConcreteMediator implements Mediator {
    private HashMap<String, Colleague> colleagueMap;
    private HashMap<String, String> interMap;

    public ConcreteMediator() {
        colleagueMap = new HashMap<String, Colleague>();
        interMap = new HashMap<String, String>();
    }

    @Override
    public void Register(String colleagueName, Colleague colleague) {
        // TODO Auto-generated method stub
        colleagueMap.put(colleagueName, colleague);

        // TODO Auto-generated method stub

        if (colleague instanceof Alarm) {
            interMap.put("Alarm", colleagueName);
        } else if (colleague instanceof CoffeeMachine) {
            interMap.put("CoffeeMachine", colleagueName);
        } else if (colleague instanceof TV) {
            interMap.put("TV", colleagueName);
        } else if (colleague instanceof Curtains) {
            interMap.put("Curtains", colleagueName);
        }

    }

    @Override
    public void GetMessage(int stateChange, String colleagueName) {
        // TODO Auto-generated method stub

        if (colleagueMap.get(colleagueName) instanceof Alarm) {
            if (stateChange == 0) {
                ((CoffeeMachine) (colleagueMap.get(interMap
                        .get("CoffeeMachine")))).StartCoffee();
                ((TV) (colleagueMap.get(interMap.get("TV")))).StartTv();
            } else if (stateChange == 1) {
                ((TV) (colleagueMap.get(interMap.get("TV")))).StopTv();
            }

        } else if (colleagueMap.get(colleagueName) instanceof CoffeeMachine) {
            ((Curtains) (colleagueMap.get(interMap.get("Curtains"))))
                    .UpCurtains();

        } else if (colleagueMap.get(colleagueName) instanceof TV) {

        } else if (colleagueMap.get(colleagueName) instanceof Curtains) {

        }

    }

}

Mediator 定义了两个方法,一个注册Colleague,另外一个获得Colleague发送过来的状态消息,
实际的Mediator类ConcreteMediator 类经过colleagueMap将注册的Colleague,经过它提供的colleagueName为key的形式保存起来,在内部判断传入的Colleague是哪一个实例,而后以本身定义的key经过interMap保存起来,以便到时候须要某个Colleague时能够经过interMap的key取出来。
而经过GetMessage处理各Colleague发送过来的状态消息,首先经过colleagueMap根据传入的colleagueName取出对应的实例,而后再根据传入的stateChange值去作相应的唤醒,经过interMap的Key能够拿到咱们须要的Colleague,这就是这里interMap的做用。

而后咱们看看Colleague:

public abstract class Colleague {
    private Mediator mediator;
    public String name;

    public Colleague(Mediator mediator, String name) {

        this.mediator = mediator;
        this.name = name;

    }

    public Mediator GetMediator() {
        return this.mediator;
    }

    public abstract void SendMessage(int stateChange);
}
public class Alarm extends Colleague {

    public Alarm(Mediator mediator, String name) {
        super(mediator, name);
        // TODO Auto-generated constructor stub
        mediator.Register(name, this);
    }

    public void SendAlarm(int stateChange) {
        SendMessage(stateChange);
    }

    @Override
    public void SendMessage(int stateChange) {
        // TODO Auto-generated method stub
        this.GetMediator().GetMessage(stateChange, this.name);
    }

}
public class CoffeeMachine extends Colleague {

    public CoffeeMachine(Mediator mediator, String name) {
        super(mediator, name);
        // TODO Auto-generated constructor stub
        mediator.Register(name, this);
    }

    @Override
    public void SendMessage(int stateChange) {
        // TODO Auto-generated method stub
        this.GetMediator().GetMessage(stateChange, this.name);
    }

    public void StartCoffee() {
        System.out.println("It's time to startcoffee!");
    }

    public void FinishCoffee() {

        System.out.println("After 5 minutes!");
        System.out.println("Coffee is ok!");
        SendMessage(0);
    }
}
public class Curtains extends Colleague {

    public Curtains(Mediator mediator, String name) {
        super(mediator, name);
        // TODO Auto-generated constructor stub
        mediator.Register(name, this);
    }

    @Override
    public void SendMessage(int stateChange) {
        // TODO Auto-generated method stub
        this.GetMediator().GetMessage(stateChange, this.name);
    }

    public void UpCurtains() {
        System.out.println("I am holding Up Curtains!");
    }

}
public class TV extends Colleague {

    public TV(Mediator mediator, String name) {
        super(mediator, name);
        // TODO Auto-generated constructor stub
        mediator.Register(name, this);
    }

    @Override
    public void SendMessage(int stateChange) {
        // TODO Auto-generated method stub
        this.GetMediator().GetMessage(stateChange, this.name);
    }

    public void StartTv() {
        // TODO Auto-generated method stub
        System.out.println("It's time to StartTv!");
    }

    public void StopTv() {
        // TODO Auto-generated method stub
        System.out.println("StopTv!");
    }
}

首先在各个具体的Colleague类的构造中须要经过mediator.Register(name, this),将Colleague注册并在mediator中保存,经过SendMessage去改变各自的状态,而后在在须要功能的Colleague中定义了各自的函数。

如今咱们来测试下:

public class MainTest {

    public static void main(String[] args) {
        Mediator mediator = new ConcreteMediator();
        Alarm mAlarm = new Alarm(mediator, "mAlarm");
        CoffeeMachine mCoffeeMachine = new CoffeeMachine(mediator,
                "mCoffeeMachine");
        Curtains mCurtains = new Curtains(mediator, "mCurtains");
        TV mTV = new TV(mediator, "mTV");
        mAlarm.SendAlarm(0);
        mCoffeeMachine.FinishCoffee();
        mAlarm.SendAlarm(1);
    }

}

首先闹钟发送一个0状态的消息给Mediator,Mediator接收到首先判断这个实例是闹钟,而后根据闹钟的状态,执行相应的唤醒,开始煮咖啡和打开电视,而后咖啡机又调用本身的FinishCoffee()方法结束煮咖啡,并发送了一个0状态的给Mediator,Mediator根据传入的实例发现时咖啡机实例,而后根据状态去将窗帘拉下,最后闹钟在发送1的状态给Mediator,Mediator将电视机关闭。

中介者模式 优势:
经过将对象彼此解耦,能够增长对象的复用性
经过将控制逻辑集中,能够简化系统维护
可让对象之间所传递的消息变得简单并且大幅减小
提升系统的灵活性,使得系统易于扩展和维护
缺点:
中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
若是设计不当,中介者对象自己变得过于复杂

适用场合: 一组对象之间的通讯方式比较复杂,致使相互依赖,结构混乱
一个对象引用不少其余对象并直接与这些对象通讯,致使难以复用该对象

中介者模式与外观模式:中介者模式注重的是内在的状态变化,而外观模式是注重的是外在的变化。

中介者模式和观察者模式:二者看起来很类似,都是经过注册而后去实现相应的行为,可是观察者模式实现的行为是固定的,而中介者模式须要实现的操做每每是须要变化的。


—————————————————————————————————————————————

二12、备忘录模式

游戏进度保存:对象状态,场景…
想一想有哪些方式:
SharedPreferences、Sqlite、Server

可是在一个大型项目每每是多人一块儿开发,若是每一个人都用各自的保存方式,在维护方面是很困难的。

思考如何设计
首先咱们必须考虑到多人开发必须得有相同的状态看管者,而且每一个开发人员之间须要保存的状态互相之间是不知道,是安全的,所以我么能够分析出下图:
这里写图片描述

首先Originator和Originator2是两个状态发起人,MementoCaretaker是状态看管者,经过saveMemento()保存两个状态发起人经过createMemento建立的MementoIF,而MementoIF是一个空接口,为何设计成一个空接口呢,这样在每一个Originator经过createMemento的MenentoIF是相互独立,互相之间都是没有任何关系的,互相之间都是不了解的。保存在MementoCaretaker中的MenentoIF经过retrieveMemento取出来,而后发起来若是须要恢复以前的状态经过restoreMemento()传入从MementoCaretaker取出的MenentoIF强转成真实的MenentoIF经过调用本身的方法获得状态。

看一个完整的备忘录模式的图例:、
这里写图片描述

客户端经过对Originator操做,Originator经过对本身实现了空接口的MementorIF的私有Mementor进行操做,Caretaker经过对空接口MementorIF进行操做,并不能对真实的Mementor进行操做,保证了数据的安全,开发的高内聚。

备忘录模式:在不破坏封装的前提下,存储关键对象的重要状态,从而能够在未来把对象还原到存储的那个状态

下面看看代码:

public interface MementoIF {

}
public class MementoCaretaker {
    private HashMap<String, MementoIF> mementomap;

    public MementoCaretaker() {
        mementomap = new HashMap<String, MementoIF>();
    }

    public MementoIF retrieveMemento(String name) {
        return mementomap.get(name);
    }

    /** * 备忘录赋值方法 */
    public void saveMemento(String name, MementoIF memento) {
        this.mementomap.put(name, memento);
    }
}
public class Originator {
    private HashMap<String, String> state;

    public Originator() {
        state = new HashMap();

    }

    public MementoIF createMemento() {
        return new Memento(state);
    }

    public void restoreMemento(MementoIF memento) {
        state = ((Memento) memento).getState();
    }

    public void showState() {
        System.out.println("now state:" + state.toString());
    }

    public void testState1() {
        state.put("blood", "500");
        state.put("progress", "gate1 end");
        state.put("enemy", "5");

    }

    public void testState2() {
        state.put("blood", "450");
        state.put("progress", "gate3 start");
        state.put("enemy", "3");

    }

    private class Memento implements MementoIF {

        private HashMap<String, String> state;

        private Memento(HashMap state) {
            this.state = new HashMap(state);
        }

        private HashMap getState() {
            return state;
        }

        private void setState(HashMap state) {
            this.state = state;
        }
    }
}
public class Originator2 {
    private ArrayList<String> state;

    public Originator2() {
        state = new ArrayList<String>();
    }

    public MementoIF createMemento() {
        return new Memento(state);
    }

    public void restoreMemento(MementoIF memento) {
        state = ((Memento) memento).getState();
    }

    public void testState1() {
        state = new ArrayList<String>();
        state.add("blood:320");
        state.add("progress:gate2 mid");
        state.add("enemy:15");

    }

    public void testState2() {
        state = new ArrayList<String>();
        state.add("blood:230");
        state.add("progress:gate8 last");
        state.add("enemy:12");

    }

    public void showState() {
        System.out.println("now state:" + state.toString());
    }

    private class Memento implements MementoIF {

        private ArrayList<String> state;

        private Memento(ArrayList<String> state) {
            this.state = new ArrayList(state);
        }

        private ArrayList<String> getState() {
            return state;
        }

        private void setState(ArrayList<String> state) {
            this.state = state;
        }
    }

}

分析代码:大体流程仍是和以前的图例同样,在MementoCaretaker 中经过传入一个key保存和取出MementoIF ,在每一个Originator中都私有化一个实现了空接口MementoIF 的类,让Originator之间互相不能状态通讯。在createMemento中经过new Memento(state),而在Memento中咱们不是直接this.state=state,这样的形式是将一个引用赋给Memnto中的state,他们是同一块地址,作不到保存的效果,因此咱们都从新new一个地址保存state,而在恢复状态经过restoreMemento参数强转成真实的Memento,经过getState()方法获得状态,为了演示两个Originator的经过两个 testState演示两个状态,经过showState演示状态。

下面看看测试代码:

public class MainTest {

    public static void main(String[] args) {
        MementoCaretaker mMementoCaretaker = new MementoCaretaker();
        Originator mOriginator = new Originator();
        Originator2 mOriginator2 = new Originator2();

        System.out.println("*****Originator*****");
        mOriginator.testState1();
        mMementoCaretaker
                .saveMemento("Originator", mOriginator.createMemento());
        mOriginator.showState();
        mOriginator.testState2();
        mOriginator.showState();
        mOriginator.restoreMemento(mMementoCaretaker
                .retrieveMemento("Originator"));
        mOriginator.showState();

        System.out.println("*****Originator 2*****");
        mOriginator2.testState1();
        mOriginator2.showState();
        mMementoCaretaker.saveMemento("Originator2",
                mOriginator2.createMemento());
        mOriginator2.testState2();
        mOriginator2.showState();
        mOriginator2.restoreMemento(mMementoCaretaker
                .retrieveMemento("Originator2"));
        mOriginator2.showState();

        //System.out.println("*****Originator&&Originator 2*****");
    //   mOriginator.restoreMemento(mMementoCaretaker
    //   .retrieveMemento("Originator2"));
    //   mOriginator.showState();

    }

}

代码分析:首先假设玩家1 mOriginator在一个状态testState1玩,使用mMementoCaretaker保存玩家1 mOriginator的mOriginator.createMemento()对象,showState 显示如今的状态,而后玩家1 mOriginator开始在另外一个状态testState2玩,showState 显示如今的状态,玩家1 mOriginator发如今testState2玩的很差,想回到testState1,mOriginator 玩家1 经过restoreMemento 获得在mMementoCaretaker保存的MementoIF,最后在经过showState 显示如今的状态
玩家2 相似,就再也不啰嗦,
先看看效果:
这里写图片描述
从图中打印能够看到确实回到了以前的状态。

以前咱们在MementoCaretaker 是经过key存储的MementoIF,因此在玩家一也能够用玩家二保存的key取出MementoIF,而后玩家一经过restoreMemento传入取出的MementoIF去恢复状态,咱们测试代码注释部分就是这样操做的,可是这样是错误的,在玩家一传入玩家二保存的MementoIF时,因为玩家二的MementoIF是彻底私有的,独立的,玩家一是根本获取不到的,因此也就没法拿到玩家二的状态,因此这里再次体现了咱们空接口MementoIF的好处,保证了数据额独立,安全。

备忘录模式:在不破坏封装的前提下,存储关键对象的重要状态,从而能够在未来把对象还原到存储的那个状态
优势:
状态存储在外面,不和关键对象混在一块儿,这能够帮助维护内聚
提供了容易实现的恢复能力
保持了关键对象的数据封装
缺点:
资源消耗上面备忘录对象会很昂贵
存储和恢复状态的过程比较耗时

注意事项: 注意开销

适用场合:
必须保存一个对象在某一个时刻的(总体或部分)状态,在对象之外的地方, 之后须要时恢复到先前的状态时


—————————————————————————————————————————————

二十3、原型模式

项目需求:银行每月底经过Email发送活动帐单给用户
特色:量大、时间要求紧
首先每封Email的标题和活动内容是相同的,只是具体的Email接收者,以及具体的内容格式是不一样的,并且每封Email的格式确定是相同的,这样咱们能够将相同的部分抽取成一个类,不一样的部分抽取出来,将相同的部分拼接按格式和不一样的部分拼接在具体位置

下面看代码:

public class EventTemplate {
    private String eventSubject, eventContent;

    public EventTemplate(String eventSubject, String eventContent) {
        this.eventSubject = eventSubject;
        this.eventContent = eventContent;
    }

    public String geteventSubject() {
        return eventSubject;
    }

    public String geteventContent() {
        return eventContent;
    }
}

subject和eventContent是相同的,分别表明标题和事件内容

public class Mail {
    private String receiver;
    private String subject;
    private String content;
    private String tail;

    public Mail(EventTemplate et) {
        this.tail = et.geteventContent();
        this.subject = et.geteventSubject();
    }

    public String getReceiver() {
        return receiver;
    }

    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    public String getTail() {
        return tail;
    }

    public void setTail(String tail) {
        this.tail = tail;
    }

}

经过抽取的EventTemplate 类获得相同的部分,将邮件内容都封装在Mail类中。

public class MainTest {
    public static void main(String[] args) {
        int i = 0;
        int MAX_COUNT = 10;
        EventTemplate et = new EventTemplate("9月份信用卡帐单", "国庆抽奖活动...");

        Mail mail = new Mail(et);

        while (i < MAX_COUNT) {
            // 如下是每封邮件不一样的地方

            mail.setContent(getRandString(5) + ",先生(女士):你的信用卡帐单..."
                    + mail.getTail());
            mail.setReceiver(getRandString(5) + "@" + getRandString(8) + ".com");
            // 而后发送邮件
            sendMail(mail);
            i++;
        }

    }

    public static String getRandString(int maxLength) {
        String source = "abcdefghijklmnopqrskuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        StringBuffer sb = new StringBuffer();
        Random rand = new Random();
        for (int i = 0; i < maxLength; i++) {
            sb.append(source.charAt(rand.nextInt(source.length())));
        }
        return sb.toString();
    }

    public static void sendMail(Mail mail) {
        System.out.println("标题:" + mail.getSubject() + "\t收件人:"
                + mail.getReceiver() + "\t内容:" + mail.getContent()
                + "\t....发送成功!");
    }

}

测试代码中经过getRandString获得随机的字母模拟用户的名字,经过sendMail简单额将Mail的内容打印,在main函数弘首先咱们定义好相同部分EventTemplate ,传入Mail类,Mail设置好不一样的部分,经过循环10次模拟发送10封邮件。

结果:
这里写图片描述

这种设计有啥问题?假若有500W邮件,每封发送时间0.1,500w*0.1s=50ws,时间消费太多了

这个时候有人确定想到多线程sendMail,可是在sendMail时咱们传入的Mail只有一个,也就是new了一次,在多线程中其中一个线程修改了Mail信息,可能会影响到下一个线程须要sendMail的具体内容,这是不安全,有人说将new Mail放在循环中,这样话Mail将会产生500W个地址,内存消耗是特别大的。

原型模式:经过复制现有实例来建立新的实例,无须知道相应类的信息

这里写图片描述
上图就是一个原型模式示例图,其实就是很简单的将new换成了clone,获得Mail的副本,而并不是new出来额Mail对象。

下面看具体代码:

public class Mail implements Cloneable {
    private String receiver;
    private String subject;
    private String content;
    private String tail;
// private ArrayList<String> ars;
    public Mail(EventTemplate et) {
        this.tail = et.geteventContent();
        this.subject = et.geteventSubject();

    }

    @Override
    public Mail clone() {
        Mail mail = null;
        try {
            mail = (Mail) super.clone();
// mail.ars = (ArrayList<String>)this.ars.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return mail;
    }

    public String getReceiver() {
        return receiver;
    }

    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    public String getTail() {
        return tail;
    }

    public void setTail(String tail) {
        this.tail = tail;
    }

}

能够看到很简单,实现Cloneable 接口,实现clone接口。按照惯例,返回的对象应该经过调用 super.clone 得到

Object类的clone方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。若是要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。

咱们看到上面代码注释的地方,ArrayList为clone不会拷贝的对象,因此咱们必须经过mail.ars = (ArrayList)this.ars.clone() 进行拷贝

原型模式:经过复制现有实例来建立新的实例,无须知道相应类的信息
优势:
使用原型模式建立对象比直接new一个对象更有效
隐藏制造新实例的复杂性
重复地建立类似对象时能够考虑使用原型模式
缺点:
每个类必须配备一个克隆方法
深层复制比较复杂

注意事项: 使用原型模式复制对象不会调用类的构造方法。因此,单例模式与原型模式是冲突的,在使用时要特别注意。

适用场合:
复制对象的结构与数据
但愿对目标对象的修改不影响既有的原型对象
建立对象成本较大的状况下


—————————————————————————————————————————————

二十4、访问者模式

项目需求:雇员管理系统。雇员的属性包括名字,收入,级别,度假天数等。雇员管理系统须要管理雇员的属性信息,而且须要管理每一个雇员的补偿。

首先使用传统的设计咱们很快能够写出以下代码:

public class Employee {

    private String name;
    private float income;
    private int vacationDays;
    private int degree;

    public Employee(String name, float income, int vacationDays, int degree) {
        this.name = name;
        this.income = income;
        this.vacationDays = vacationDays;
        this.degree = degree;
    }

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

    public String getName() {
        return name;
    }

    public void setIncome(float income) {
        this.income = income;
    }

    public float getIncome() {
        return income;
    }

    public void setVacationDays(int vacationDays) {
        this.vacationDays = vacationDays;
    }

    public int getVacationDays() {
        return vacationDays;
    }

    public void setDegree(int degree) {
        this.degree = degree;
    }

    public int getDegree() {
        return degree;
    }

}
public class Employees {
    private HashMap<String, Employee> employees;

    public Employees() {
        employees = new HashMap<String, Employee>();
    }

    public void Attach(Employee employee) {
        employees.put(employee.getName(), employee);
    }

    public void Detach(Employee employee) {
        employees.remove(employee);
    }

    public Employee getEmployee(String name) {
        return employees.get(name);
    }

    public void getCompensation() {
        for (Employee employee : employees.values()) {

            System.out
                    .println(employee.getName()
                            + "'s Compensation is "
                            + (employee.getDegree()
                                    * employee.getVacationDays() * 100));

        }

    }
}

Employee 为雇员类,其中包括须要包含的属性,Employees 为管理系统,经过HashMap管理各个Employee ,并经过遍历HashMap 经过getCompensation()方法管理补偿信息,根据等级getDegree*度假天数getVacationDays*10= 获得补偿的金额。

下面测试下:

public class MainTest {
    public static void main(String[] args) {
        Employees mEmployees = new Employees();

        mEmployees.Attach(new Employee("Tom", 4500, 8, 1));
        mEmployees.Attach(new Employee("Jerry", 6500, 10, 2));
        mEmployees.Attach(new Employee("Jack", 9600, 12, 3));
        mEmployees.getCompensation();
    }

}

如今补偿给每一个员工的方式不使用原来的根据等级*度假天数*10获得补偿的金额,那么咱们如今须要在管理系统类Employees 修改getCompensation()可是这破坏了开闭原则。其实我也想到了能够将Employee 类抽象,增长一个getCompensation()的抽象方法,每一个雇员经过继承自抽象的Employee类去实现本身对应的补偿方式,而后Employees 管理系统只要对应的调用Employee 的getCompensation方法便可,可是我发现经过继承,每次雇员类都须要将name,income等等属性都从新继承,而他们变化的却只有补偿的方式,可是访问者模式就很好的解决了这个问题。

那么好吧,咱们如今看看访问者模式设计这个项目的图例:
这里写图片描述
经过加入一个接口访问者类Visitor,并提供一个抽象的visit()方法传入须要访问的雇员类,这样就能知道具体在访问哪一个雇员,在具体的ConcreteVisitor访问者类中实现visit()方法,经过visit()传入的参数去管理雇员的补偿信息,而在雇员类Employee 中添加一个Accept方法,传入Visitor做为参数,这样雇员类就能知道具体是哪一个Visitor访问了本身,这样实现了双重指定,在雇员类中知道本身的访问者是谁,访问者中知道本身须要访问的雇员类是谁。

假如如今须要新的补偿类,咱们须要从新实现Visitor类,获得具体的Visitor类,而后传入Employee,这样Employee就能够拿到新的补偿方式,这样咱们就遵照了开闭原则。

下面看一张完整的访问者模式图例:
这里写图片描述
在上图例中,访问者被访问者都被抽取成接口,这样有利于扩展,不管你是雇员仍是前雇员仍是什么,只要实现了Element类,均可以拿到本身的访问者,而访问者中不管本身是什么方式的访问者只要实现了Visitor均可以获得被访问者。使用了双重指定。

访问者模式:对于一组对象,在不改变数据结构的前提下,增长做用于这些结构元素新的功能。
适用于数据结构相对稳定,它把数据结构和做用于其上的操做解耦,使得操做集合能够相对自由地演化

下面看看具体的代码:

public interface Visitor {
    abstract public void Visit( Element element );

}
public class CompensationVisitor implements Visitor {

    @Override
    public void Visit(Element element) {
        // TODO Auto-generated method stub
        Employee employee = ((Employee) element);

        System.out.println(employee.getName() + "'s Compensation is "
                + (employee.getDegree() * employee.getVacationDays() * 10));
    }

}
public abstract class Element {
    abstract public void Accept(Visitor visitor);
}
public class Employee extends Element {

    private String name;
    private float income;
    private int vacationDays;
    private int degree;

    public Employee(String name, float income, int vacationDays, int degree) {
        this.name = name;
        this.income = income;
        this.vacationDays = vacationDays;
        this.degree = degree;
    }

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

    public String getName() {
        return name;
    }

    public void setIncome(float income) {
        this.income = income;
    }

    public float getIncome() {
        return income;
    }

    public void setVacationDays(int vacationDays) {
        this.vacationDays = vacationDays;
    }

    public int getVacationDays() {
        return vacationDays;
    }

    public void setDegree(int degree) {
        this.degree = degree;
    }

    public int getDegree() {
        return degree;
    }

    @Override
    public void Accept(Visitor visitor) {
        // TODO Auto-generated method stub
        visitor.Visit(this);
    }

}

Element 抽取出来以后,这样就不仅单单能够管理雇员类,但凡实现了Element Visitor 就能进行对它访问,而对于Visitor 只要实现了Visitor ,Element 就能获得本身的补偿方式。

public class Employees {
    private HashMap<String, Employee> employees;

    public Employees() {
        employees = new HashMap();
    }

    public void Attach(Employee employee) {
        employees.put(employee.getName(), employee);
    }

    public void Detach(Employee employee) {
        employees.remove(employee);
    }

    public Employee getEmployee(String name) {
        return employees.get(name);
    }

    public void Accept(Visitor visitor) {
        for (Employee e : employees.values()) {
            e.Accept(visitor);
        }
    }
}

管理系统类Employees 增长了Accept,经过传入Visitor ,遍历employees,将传入的Visitor 在传入每一个Employee ,Employee 经过Accept(),而后经过传入的visitor的Visit去最终获得Employee 的补偿信息。

以前我也想过为了节省代码,在Element 中只须要定一个一个空接口,每一个Element 无需实现Accept拿到访问者,在管理系统类中拿到Employee 后,直接经过visitor.Visit(Employee );的形式,也就是像这样:

public void Accept(Visitor visitor) {
        for (Employee e : employees.values()) {
            visitor.Visit(e);
        }
    }
}

这样能够节省代码,可是我后来想一想在Employee 中就不知道哪一个visitor访问了它,这样就不符合实际意义。

public class MainTest {
    public static void main(String[] args) {
        Employees mEmployees = new Employees();

        mEmployees.Attach(new Employee("Tom", 4500, 8, 1));
        mEmployees.Attach(new Employee("Jerry", 6500, 10, 2));
        mEmployees.Attach(new Employee("Jack", 9600, 12, 3));

        mEmployees.Accept(new CompensationVisitor());

    }

}

经过指定额访问者获得补偿结果。假如须要改变补偿方式,只须要从新实现Visitor(),传入新的访问者。结果和以前也是同样的。可是如今经过访问者有利于扩展,而且遵照开闭原则。

访问者模式:对于一组对象,在不改变数据结构的前提下,增长做用于这些结构元素新的功能。

优势:
符合单一职责原则
扩展性良好
有益于系统的管理和维护
缺点:
增长新的元素类变得很困难
破坏封装性

注意事项: 系统有比较稳定的数据结构
与迭代器的关系。在迭代器模式中咱们也是遍历许多对象,可是在迭代器模式中咱们并不需知道每一个对象须要具体的操做。

适用场合: 若是一个系统有比较稳定的数据结构,又有常常变化的功能需求,那么访问者模式就是比较合适的


—————————————————————————————————————————————

二十5、设计模式总结

1、什么是设计模式

模式:在某些场景下,针对某类问题的某种通用解决方案
场景:项目环境
问题:约束条件,项目目标等
解决方案:通用、能够复用的设计,解决约束,达到目标

2、设计模式的三个分类

2.1 建立型模式:对象实例化的模式,建立型模式解耦了对象的实例化过程

简单工厂:一个工厂类根据传入的参量决定建立出哪种产品类的实例
工厂方法:定义一个建立对象的接口,让子类决定实例化哪个类
抽象工厂:建立相关或依赖对象的家族,而无需明确指定具体类
单例模式:某个类只能有一个实例,提供一个全局访问点
生成器模式:封装一个复杂对象的构建过程,并能够按步骤构造
原型模式:经过复制现有的实例来建立新的实例

2.2 结构型模式:把类或对象结合在一块儿造成更大的结构

适配器模式:将一个类的方法接口转换成客户但愿的另一个接口
组合模式:将对象组合成树形结构以表示“部分-总体”的层次结构
装饰模式:动态地给对象添加新的功能
代理模式:为其余对象提供一个代理以控制对这个对象的访问
蝇量模式:经过共享技术有效地支持大量细粒度的对象
外观模式:提供统一的方法来访问子系统的一群接口
桥接模式:将抽象部分与它的实现部分分离,使它们均可以独立地变化

2.3 行为型模式:类和对象如何交互,及划分责任和算法

模板模式:定义一个算法结构,而将一些步骤延迟到子类中实现
解释器模式:给定一个语言, 定义它的文法的一种表示,并定义一个解释器
策略模式:定义一系列的算法,把它们封装起来, 而且使它们可相互替换
状态模式:容许一个对象在其内部状态改变时改变它的行为
观测者模式:对象间的一对多的依赖关系
备忘录模式:在不破坏封装性的前提下,保存对象的内部状态
中介者模式:用一个中介对象来封装一系列的对象交互
命令模式:将命令请求封装为一个对象,使得可用不一样的请求来进行参数化
访问者模式:在不改变数据结构的前提下,增长做用于一组对象元素新的功能
责任链:请求发送者和接收者之间解耦,使的多个对象都有机会处理这个请求
迭代器:一种遍历访问聚合对象中各个元素的方法,不暴露该对象的内部结构

3、设计模式的六大原则

3.1 组合复用原则

多用组合,少用继承
找到变化部分,抽象,封装变化
区分“Has-A”与“Is-A”若是HasA表示你有它应该使用组合,IsA表示你是它应该使用继承。

3.2 依赖倒置原则

依赖:成员变量、方法参数、返回值
要依赖于抽象,不要依赖于具体
高层模块不该该依赖低层模块,两者都应该依赖其抽象
抽象不该该依赖具体,具体应该依赖抽象
针对接口编程,不要针对实现编程

以抽象为基础搭建的结构比具体类搭建的结构要稳定的多
在java中,抽象指的是接口或者抽象类,具体就是具体的实现类

3.3 开闭原则

对扩展开放,对修改关闭
经过扩展已有软件系统,能够提供新的功能
修改的关闭,保证稳定性和延续性

3.4 迪米特法则

一个对象应该与其余对象保持最少的了解。只与直接朋友交谈。
成员变量、方法参数、方法返回值中须要的类为直接朋友
类与类之间的关系越密切了解越多,耦合度越大
尽可能下降类与类之间的耦合
外观模式、中介者模式

接口隔离原则:一个类对另外一个类的依赖应该创建在最小的接口上

3.5 里氏替换原则

全部引用基类的地方必须能透明地使用其子类对象
子类在扩展父类功能时不能破坏父类原有的功能
使用继承时,遵循里氏替换原则:
子类能够实现父类的抽象方法,但不能覆盖父类的非抽象方法。
当子类重载父类方法时,方法的形参要比父类方法的参数更宽松
当子类实现父类的抽象方法时,方法的返回值要比父类更严格

里氏替换原则是设计整个继承体系的原则

3.6 单一职责原则

类应该只有一个致使类变动的理由
即一个类只负责一项职责

下降类的复杂度
提升系统的可维护性
修改时下降风险溢出

4、用模式来思考

4.1 保持简单

尽量用最简单的方式解决问题
简单而弹性的设计,通常使用模式是最好的方法

4.2 设计模式非万能

模式是通用问题的经验总结
使用模式时要考虑它对其余部分的影响
不须要预留任何弹性的时候,删除掉模式
平衡与妥协

4.3 什么时候须要模式

找出设计中会变化的部分,一般就是须要考虑模式的地方
重构时

4.4 重构的时间就是模式的时间

重构就是改变代码来改进组织方式的过程
利用模式来重构

源码下载