软件工程 | 设计模式Java版

软件工程 | 设计模式Java版

前置知识

面向方针(oo) => 功用模块[规划形式+算法(数据结构)] => 结构[多种规划形式] => 架构[服务器集群]

高内聚低耦合:重用性、可读性、可扩展性、可靠性

规划准则:

  • 单一责任准则(Principle of Single Responsibility)- 交通东西比方
  • 接口阻隔准则(Interface Segregation Principle)- A-I12-B/C-I13-D比方
  • 依靠倒转准则(Dependence Inversion Principle)- 接口办法/结构办法/setter办法传递 Person-IReceiver-Email/Weinxin比方和电视问题
  • 里氏替换准则(Liskov Substitution Principle)- 解决子类修正父类办法问题-原有承继去掉(依靠/聚合/组合)
  • 敞开封闭准则(Open Close Principle)- 扩展敞开(供给方),修正封闭(运用方)-GF.DrawShap/abstract Shape.draw();/yuan sanjiao比方
  • 迪米特法则(最少知道准则)(Demeter Principle)- A依靠B(依靠关系B不能是局部变量)
  • 组成复用准则 – 运用组成/聚合的办法,而不是运用承继
//依靠倒转案例
//第一种办法:接口传递
//开关的接口
interface IOpenAndClose {
    public void opoen(ITV tv);//笼统办法,接纳接口
}
interface ITV {//ITV接口
    public void play();
}
//完结接口
class OpenAndColse implements IOpenAndClose {
    @Override
    public void opoen(ITV tv) {
        tv.play();
    }
}
//办法二:结构办法传递
interface IOpenAndClose {
    public void open();//笼统办法
}
interface ITV {//ITV接口
    public void play();
}
class OpenAndClose implements IOpenAndClose {
    public ITV tv;//成员
    public OpenAndClose(ITV tv) {//结构办法
        this.tv = tv;
    }
    @Override
    public void open() {
        this.tv.play();
    }
}
//办法三:setter办法传递
interface IOpenAndClose {
    public void open();//笼统办法
}
interface ITV {//ITV接口
    public void play();
}
class OpenAndClose implements IOpenAndClose {
    private ITV tv;
    public void setTv(ITV tv) {
        this.tv = tv;
    }
    @Override
    public void open() {
        this.tv.play();
    }
}

UML类图——Unified modeling language UML(统一建模语言),是一种用于软件系统剖析和规划的语言东西。【依靠、泛化(承继)、完结、关联、聚合与组合

软件工程 | 设计模式Java版

规划形式

软件工程 | 设计模式Java版

单例形式

1)饿汉式(静态常量)

进程如下:
1)结构器私有化(防止new)
2)类的内部创立方针
3)向外暴露一个静态的公共办法。getInstance
4)代码完结

public class SingletonTest1 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2);
    }
}
//饿汉式(静态常量)
class Singleton {
    //1、结构器私有化,外部不能new
    private Singleton() {}
    //2、本类内部创立方针实例
    private final static Singleton instance = new Singleton();
    //3、供给一个公有的静态办法,回来实例方针
    public static Singleton getInstance() {
        return instance;
    }
}

在类装载的时分就完结实例化,防止线程同步问题。没有到达Lazy Loading的效果,会形成内存浪费。
留意类加载时机:new一个方针、拜访类的静态成员、调用类的静态办法、给类的静态成员赋值、程序的主类、反射

2)饿汉式(静态代码块)

public class SingletonTest2 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2);
    }
}
//饿汉式(静态代码块)
class Singleton {
    //1、结构器私有化,外部不能new
    private Singleton() {}
    //2、静态代码块
    private static Singleton instance;
    static {
        instance = new Singleton();
    }
    //3、供给一个公有的静态办法,回来实例方针
    public static Singleton getInstance() {
        return instance;
    }
}

3)懒汉式(线程不安全)

public class SingletonTest3 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2);
    }
}
//懒汉式(线程不安全)
class Singleton {
    private static Singleton instance;
    private Singleton() {}
    //供给一个静态的公有办法,当运用到该办法时,才去创立instance
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

起到了Lazy Loading的效果,可是只能在单线程下运用。【不主张运用】

4)懒汉式(线程安全,同步办法)

public class SingletonTest4 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2);
    }
}
//懒汉式(线程安全,同步办法)
class Singleton {
    private static Singleton instance;
    private Singleton() {}
    //供给一个静态的公有办法,参加同步处理的代码,解决线程安全问题
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

加锁synchronized,办法进行同步功率太低。【不推荐运用】

5)懒汉式(线程安全,同步代码块)

public class SingletonTest5 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2);
    }
}
//懒汉式(线程安全,同步代码块)
class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}

这种同步并不能起到线程同步的效果。【不能运用】

6)两层查看

public class SingletonTest6 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2);
    }
}
//两层查看
class Singleton {
    private static volatile Singleton instance;
    private Singleton() {}
    //供给一个静态的公有办法,参加两层查看代码,解决线程安全问题,一起解决懒加载问题
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

volatile和synchronized,线程安全;延迟加载;功率较高。【推荐运用】

7)静态内部类

public class SingletonTest7 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2);
    }
}
//静态内部类
class Singleton {
    private Singleton() {}
    //写一个静态内部类,该类中有一个静态特点Singleton
    private static class singleInstance {
        private static final Singleton INSTANCE = new Singleton();
    }
    //供给一个静态的公有办法,直接回来方针
    public static synchronized Singleton getInstance() {
        return singleInstance.INSTANCE;
    }
}

采用了类装载的机制来确保初始化实例时只有一个线程。静态内部类办法在Singleton类被装载时并不会当即实例化,而是在需求实例化时,调用getInstance办法,才会装载SingletonInstance类,然后完结Singleton的实例化。类的静态特点只会在第一次加载类的时分初始化,所以在这儿,JVM协助咱们确保了线程的安全性,在类进行初始化时,别的线程是无法进入的
防止了线程不安全,利用静态内部类特点完结延迟加载,功率高。【推荐运用】

8)枚举

public class SingletonTest8 {
    public static void main(String[] args) {
        Singleton instance = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance == instance2);
        instance.sayOK();
    }
}
//运用枚举,能够完结单例
enum Singleton {
    INSTANCE;//特点
    public void sayOK() {
        System.out.println("ok");
    }
}

借助JDK1.5中添加的枚举来完结单例形式。不仅能防止多线程同步问题,而且还能防止反序列化从头创立新的方针。【推荐运用】

单例形式运用的场景:需求频频的进行创立和毁掉的方针、创立方针时耗时过多或 耗费资源过多(即:重量级方针),但又经常用到的方针、东西类方针、频频拜访数据库或义件的方针(比方数据源、session工厂等)

工厂形式

在软件开发中,当咱们会用到很多的创立某种、某类或许某批方针时,就会运用到工厂形式。

简略工厂形式

界说了一个创立方针的类,由这个类来封装实例化方针的行为(代码)。

软件工程 | 设计模式Java版

//把Pizza类做成笼统类
public abstract class Pizza {
    private 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;
    }
}
// GreekPizza CheessPizza ... 披萨品种
public class GreekPizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("给GreekPizza预备原材料");
    }
}
public class OrderPizza {
    //结构办法
    public OrderPizza() {
        Pizza pizza = null;
        String orderType;//订货披萨的类型
        do {
            orderType = getType();
            if (orderType.equals("greek")) {
                pizza = new GreekPizza();
                pizza.setName("GreekPizza");
            } else if (orderType.equals("cheess")) {
                pizza = new CheessPizza();
                pizza.setName("CheessPizza");
            } else {
                break;
            }
            //输出pizza制造进程
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }
    //写一个办法,能够获取客户期望订货的披萨品种
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String str = null;
            str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}
//相当于客户端
public class OrderStore {
    public static void main(String[] args) {
        OrderPizza orderPizza = new OrderPizza();
    }
}

改进的思路剖析

  • 剖析:修正代码能够承受,可是如果咱们在其它的当地也有创立Pizza的代码,就意味着,也需求修正,而创立Pizza的代码,往往有多处。
  • 思路:把创立Pizza方针封装到一个类中,这样咱们有新的Pizza品种时,只需求修正该类就可,其它有创立到Pizza方针的代码就不需求修正了(运用简略工厂形式)。
//简略工厂类
public class SimpleFactory {
    //简略工厂形式,也叫静态工厂形式,能够用static润饰该办法
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if (orderType.equals("greek")) {
            pizza = new GreekPizza();
            pizza.setName("GreekPizza");
        } else if (orderType.equals("cheess")) {
            pizza = new CheessPizza();
            pizza.setName("CheessPizza");
        }
        //输出pizza制造进程
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}
public class OrderPizza2 {
    //界说一个简略工厂方针
    SimpleFactory simpleFactory;
    //结构器
    public OrderPizza2(SimpleFactory simpleFactory) {
        setFactory(simpleFactory);
    }
    Pizza pizza = null;
    public void setFactory(SimpleFactory simpleFactory) {
        String orderType = "";//用户输入的
        this.simpleFactory = simpleFactory;//设置简略工厂方针
        do {
            orderType = getType();
            pizza = this.simpleFactory.createPizza(orderType);
            //输出pizza制造进程
            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println("订货失利");
                break;
            }
        } while (true);
    }
    //写一个办法,能够获取客户期望订货的披萨品种
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String str = null;
            str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}
//相当于客户端
public class OrderStore {    
  public static void main(String[] args) {        
    OrderPizza2 orderPizza = new OrderPizza2(new SimpleFactory());    
  }
}

工厂办法形式

工厂办法形式规划方案:将披萨项目的实例化功用笼统成笼统办法,在不同的口味点餐子类中详细完结。
工厂办法形式:界说了一个创立方针的笼统办法,由子类决定要实例化的类。工厂办法形式将方针的实例化推迟到子类。

软件工程 | 设计模式Java版

public class BJCheessPizza extends Pizza {
    @Override
    public void prepare() {
        setName("北京的CheessPizza");
        System.out.println("  北京的CheessPizza 预备原材料");
    }
}
public class BJPepperPizza extends Pizza {...}
public class LDCheessPizza extends Pizza {...}
public class LDPepperPizza extends Pizza {...}
public abstract class OrderPizza {
    //结构办法
    public OrderPizza() {
        Pizza pizza = null;
        String orderType;//订货披萨的类型
        do {
            orderType = getType();
            //调用办法
            pizza = creatPizza(orderType); //让子类的笼统办法完结
            //输出pizza制造进程
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }
    //界说一个笼统办法,让各个工厂子类自己完结
    abstract Pizza creatPizza(String orderType);
    //写一个办法,能够获取客户期望订货的披萨品种
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String str = null;
            str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}
public class BJOrderPizza  extends OrderPizza {
    @Override
    Pizza creatPizza(String orderType) {
        Pizza pizza=null;
        if (orderType.equals("Cheess")){
            pizza=new BJCheessPizza();  
        }else if(orderType.equals("Pepper")){
            pizza=new BJPepperPizza();
        }
        return pizza;
    }
}
public class LDOrderPizza extends OrderPizza {
    pizza = new LDCheessPizza();
    pizza = new LDPepperPizza();
}
//披萨店
public class PizzaStore {
    public static void main(String[] args) {
        new BJOrderPizza();//创立北京各种口味的披萨
        new LDOrderPizza();//创立伦敦各种口味的披萨
    }
}

笼统工厂形式

笼统工厂形式:界说了一个interface用于创立相关或有依靠关系的方针簇,而无需指明详细的类。

笼统工厂形式能够将简略工厂形式和工厂办法形式进行整合。从规划层面看,笼统工厂形式便是对简略工厂形式的改进(或许称为进一步的笼统)

将工厂笼统成两层,AbsFactory(笼统工厂)和详细完结的工厂子类。程序员能够根据创立方针类型运用对应的工厂子类。这样将单个的简略工厂类变成了工厂簇,更利于代码的维护和扩展。

软件工程 | 设计模式Java版

//一个笼统工厂形式的笼统层(接口)
public interface AbsFactory {
    //让下面的工厂子类来详细完结
    Pizza createPizza(String orderType);
}
//这是一个工厂子类
public class BJFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if (orderType.equals("Cheess")) {
            pizza = new BJCheessPizza();
        }
        if (orderType.equals("Pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}
public class LDFactory implements AbsFactory {
...
    pizza=new LDCheessPizza();
    pizza=new LDPepperPizza();
...
}
public class OrderPizza {
    AbsFactory factory;
    //结构器
    public OrderPizza(AbsFactory factory) {
        setFactory(factory);
    }
    private void setFactory(AbsFactory factory) {
        Pizza pizza = null;
        String orderType = "";//用户输入
        this.factory = factory;
        do {
            orderType = getType();
            //factory可能是北京的工厂子类,也可能是伦敦的工厂子类
            pizza = factory.createPizza(orderType);
            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.box();
                pizza.cut();
            } else {
                System.out.println("订货失利");
                break;
            }
        } while (true);
    }
    //写一个办法,能够获取客户期望订货的披萨品种
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String str = null;
            str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}
public class PizzaStore {
    public static void main(String[] args) {
        new OrderPizza(new BJFactory());
        //new OrderPizza(new LDFactory());
    }
}

原型形式

Java中object类是一切类的根类,object类供给了一个clone()办法,该办法能够将一个Java方针仿制一份,可是需求完结clone的Java类必须要完结一个接口Cloneable,该接口表明该类能够仿制且具有仿制的才能 => 原型形式。

1)原型形式(Prototype形式)是指:用原型实例指定创立方针的品种,并且经过仿制这些原型,创立新的方针
2)原型形式是一种创立型规划形式,答应一个方针再创立别的一个可定制的方针,无需知道怎么创立的细节
3)作业原理是:经过将一个原型方针传给那个要发起创立的方针,这个要发起创立的方针经过恳求原型方针仿制它们自己来实施创立,即 方针.clone()

public class Sheep implements Cloneable {
    private String name;
    private int age;
    private String color;
    public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }
    //get、set办法
    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ",\'' +
                '}';
    }
    //克隆该实例,运用默许的clone办法来完结
    @Override
    protected Object clone() {
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println(e.getMessage());
        }
        return sheep;
    }
}
public class Client {
    public static void main(String[] args) {
        Sheep sheep = new Sheep("tom", 1, "白色");
        Sheep sheep2 = (Sheep) sheep.clone();
        Sheep sheep3 = (Sheep)sheep.clone();
        //......
        System.out.println(sheep);
        System.out.println(sheep2);
        System.out.println(sheep3);
    }
}

浅仿制
1)关于数据类型是根本数据类型的成员变量,浅仿制会直接进行值传递,也便是将 该特点值仿制一份给新的方针。
2)关于数据类型是引证数据类型的成员变量,比方说成员变量是某个数组、某个类 的方针等,那么浅仿制会进行引证传递,也便是仅仅将该成员变量的引证值(内存地址)仿制一份给新的方针。由于实际上两个方针的该成员变量都指向同一个实例。在这种情况下,在一个方针中修正该成员变量会影响到另一个方针的该成员变量值
3)浅仿制是运用默许的clone()办法来完结sheep = (Sheep) super.clone();

深仿制
1)仿制方针的一切根本数据类型的成员变量值。
2)为一切引证数据类型的成员变量中请存储空间,并仿制每个引证数据类型成员变量所引证的方针,直到该方针可达的一切方针。也便是说,方针进行深仿制要对整个方针进行仿制
3)深仿制完结办法:重写clone办法来完结深仿制;经过方针序列化完结深仿制。

public class DeepCloneableTarget implements Serializable, Cloneable {
	private static final long serialVersionUID = 1L;
	private String cloneName;
	private String cloneClass;
	public DeepCloneableTarget(String cloneName, String cloneClass) {
		this.cloneName = cloneName;
		this.cloneClass = cloneClass;
	}
	//由于该类的特点都是String,因而咱们这儿运用默许的clone完结即可
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
public class DeepProtoType implements Serializable, Cloneable {
    public String name;
    public DeepCloneableTarget deepCloneableTarget;
    public DeepProtoType() {
        super();
    }
    //深仿制-办法1
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object deep = null;
        //完结对特点为根本数据类型和String的克隆
        deep = super.clone();
        //对特点为引证类型的独自处理
        DeepProtoType deepProtoType = (DeepProtoType) deep;
        deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
        return deepProtoType;
    }
    //深仿制-办法2
    public Object deepClone() {
        //创立流方针
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this); //把当时这个方针以方针流的办法输出
            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            DeepProtoType copyObj = (DeepProtoType) ois.readObject();
            return copyObj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            //封闭流
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (Exception e2) {
                System.out.println(e2.getMessage());
            }
        }
    }
}
public class Client {
    public static void main(String[] args) throws Exception {
        DeepProtoType p = new DeepProtoType();
        p.name = "宋江";
        p.deepCloneableTarget = new DeepCloneableTarget("小明", "学生类");
        //测验,办法1
        DeepProtoType p1 = (DeepProtoType) p.clone();
        System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
        System.out.println("p1.name=" + p.name + "p2.deepCloneableTarget=" + p1.deepCloneableTarget.hashCode());
        //测验,办法2
        DeepProtoType p2 = (DeepProtoType) p.deepClone();
        System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
        System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());
    }
}

制造者形式

1)制造者形式(Builder Pattern)又名生成器形式,是一种方针构建形式。它能够将杂乱方针的制造进程笼统出来(笼统类别),使这个笼统进程的不同完结办法能够结构出不同体现(特点)的方针。
2)制造者形式是一步一步创立一个杂乱的方针,它答应用户只经过指定杂乱方针的类型和内容就能够构建它们,用户不需求知道内部的详细构建细节。【模块组装

制造者形式的四个人物
1)Product (产品人物):一个详细的产品方针。
2)Builder(笼统制造者):创立一个Product方针的各个部件指定的接口。
3)ConcreteBuilder(详细制造者):完结接口,构建和装配各个部件。
4) Director(指挥者)::构建一个运用Builder接口的方针。它主要是用于创立一个杂乱的方针。它主要有两个效果,一是:阻隔了客户与方针的生产进程,二是:负责操控产品方针的生产进程。

软件工程 | 设计模式Java版

//产品-->Product
publicclassHouse{
privateStringbaise;
privateStringwall;
privateStringroofed;
    ...getter/setter
}
//笼统的制造者
publicabstractclassHouseBuilder{
protectedHousehouse=newHouse();
//将制造的流程写好,笼统的办法
publicabstractvoidbuildBasic();
publicabstractvoidbuildWalls();
publicabstractvoidroofed();
//制造房子后,将产品(房子)回来
publicHousebuildHouse(){
returnhouse;
}
}
publicclassCommonHouseextendsHouseBuilder{
@Override
publicvoidbuildBasic(){
System.out.println("一般房子打地基5米");
}
@Override
publicvoidbuildWalls(){
System.out.println("一般房子垒墙10cm");
}
@Override
publicvoidroofed(){
System.out.println("一般房子房顶");
}
}
publicclassHighBuildingextendsHouseBuilder{
@Override
publicvoidbuildBasic(){
System.out.println("楼房的打地基100米");
}
@Override
publicvoidbuildWalls(){
System.out.println("楼房的垒墙20cm");
}
@Override
publicvoidroofed(){
System.out.println("楼房的通明房顶");
}
}
//指挥者,指定制造流程
publicclassHouseDirector{
HouseBuilderhouseBuilder=null;
//经过结构器传入houseBuilder
publicHouseDirector(HouseBuilderhouseBuilder){
this.houseBuilder=houseBuilder;
}
//或许经过set办法传入houseBuilder
publicvoidsetHouseBuilder(HouseBuilderhouseBuilder){
this.houseBuilder=houseBuilder;
}
//怎么处理制造房子的流程?交给指挥者
publicHouseconstructHouse(){
houseBuilder.buildBasic();
houseBuilder.buildWalls();
houseBuilder.roofed();
returnhouseBuilder.buildHouse();
}
}
publicclassClient{
publicstaticvoidmain(String[]args){
CommonHousecommonHouse=newCommonHouse();//盖一般房子
//HighBuildinghighBuilding=newHighBuilding();//盖高房子
HouseDirectorhouseDirector=newHouseDirector(commonHouse);//创立房子的指挥者
Househouse=houseDirector.constructHouse();//完结盖房,回来产品(房子)
}
}

署理形式

署理形式:为一个方针供给一个替身,以操控对这个方针的拜访。即经过署理方针拜访方针方针。这样做的优点是:能够在方针方针完结的基础上,增强额定的功用操作,即扩展方针方针的功用。

署理形式有不同的形式,主要有三种静态署理、动态署理(JDK署理或接口署理)和cglib署理(在内存动态的创立方针,而不需求完结接口)

静态署理

静态署理在运用时,需求界说接口或许父类,被署理方针(即方针方针)与署理方针一起完结相同的接口或许是承继相同父类。

软件工程 | 设计模式Java版

publicinterfaceITeacherDao{
voidteach();//授课的办法
}
//被署理方针
publicclassTeacherDaoimplementsITeacherDao{
@Override
publicvoidteach(){
System.out.println("教师授课中...");
}
}
 //署理方针
 publicclassTeacherDaoProxyimplementsITeacherDao{
 privateITeacherDaoiTeacherDao;
 publicTeacherDaoProxy(ITeacherDaoiTeacherDao){
 this.iTeacherDao=iTeacherDao;
 }
@Override
publicvoidteach(){
System.out.println("教师备课");
iTeacherDao.teach();
System.out.println("教师完毕讲课");
}
}
 publicclassClient{
 publicstaticvoidmain(String[]args){
 //创立被署理方针(方针方针)
 TeacherDaoteacherDao=newTeacherDao();
 //创立署理方针,一起将被署理方针传递给署理方针
 TeacherDaoProxyteacherDaoProxy=newTeacherDaoProxy(teacherDao);
 //经过署理方针,调用到被署理方针的办法
 teacherDaoProxy.teach();
 }
}

优点:在不修正方针方针的功用前提下,能经过署理方针对方针功用扩展
缺点:一旦接口添加办法,方针方针与署理方针都要维护。

动态署理-JDK署理

署理方针,不需求完结接口,可是方针方针要完结接口,不然不能用动态署理。
署理方针的生成,是利用JDK的API,动态的在内存中构建署理方针。【反射机制】
署理类地点包:java.lang.reflect.Proxy。JDK完结署理只需求运用newProxyInstance办法,可是该办法需求接纳三个参数,完好的写法是:
static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces, InvocationHandler h)

软件工程 | 设计模式Java版

 importjava.lang.reflect.InvocationHandler;
 importjava.lang.reflect.Method;
 importjava.lang.reflect.Proxy;
 publicclassProxyFactory{
 privateObjecttarget;//方针方针
 publicProxyFactory(Objecttarget){
this.target=target;
}
//给方针方针生成一个署理方针
publicObjectgetProxyInstance(){
/**
*newProxyInstance办法参数阐明
 *第一个参数:指定当时方针方针运用的类加载器;
 *第二个参数:方针方针完结的接口类型;
*第三个参数:事情处理,履行方针方针的办法时,会触发事情处理器办法
*/
returnProxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
newInvocationHandler(){
@Override
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{
System.out.println("教师备课");
//反射机制调用方针方针的办法
Objectinvoke=method.invoke(target,args);
System.out.println("教师讲完课了");
returninvoke;
}
}
);
}
}
public class Clinet {
    public static void main(String[] args) {
        // 创立方针方针
        ITeacherDao target = new TeacherDao();
        // 给方针方针 创立署理方针
        ITeacherDao proxyInstance = (ITeacherDao) new ProxyFactory(target).getProxyInstance();
        // 内存中动态生成署理方针 proxyInstance class com.sun.proxy.$Proxy0
        System.out.println("proxyInstance "+proxyInstance.getClass());
        // 经过署理方针 调用方针方针
        proxyInstance.teach();
    }
}

动态署理-CGlib署理

被署理方针不运用接口,运用办法拦截器
在AOP编程中怎么挑选署理形式:

  1. 方针方针需求完结接口,用JDK署理
  2. 方针方针不需求完结接口,用cglib署理

cglib包的底层是经过运用字节码处理结构ASM转换字节码并生成新的类

asm.jar
asm-commons.jar
asm-tree.jar
cglib-2.2.jar

在内存中动态构建子类,留意署理的类不能为final,不然报错java.lang.lllegalArgumentException

软件工程 | 设计模式Java版

publicclassTeacherDao{
publicvoidteach(){
System.out.println("教师授课中...");
}
}
 importnet.sf.cglib.proxy.Enhancer;
 importnet.sf.cglib.proxy.MethodInterceptor;
 importnet.sf.cglib.proxy.MethodProxy;
 importjava.lang.reflect.Method;
 publicclassProxyFactoryimplementsMethodInterceptor{
 privateObjecttarget;//维护一个方针方针
//结构器,传入被署理方针
publicProxyFactory(Objecttarget){
this.target=target;
}
//回来一个署理方针
publicObjectgetProxyInstance(){
//1、创立一个东西类
Enhancerenhancer=newEnhancer();
 //2、设置父类
enhancer.setSuperclass(target.getClass());
//3、设置回调函数
enhancer.setCallback(this);
//4、创立子类方针,即署理方针
returnenhancer.create();
}
@Override
publicObjectintercept(Objecto,Methodmethod,Object[]args,MethodProxymethodProxy)throwsThrowable{
 System.out.println("教师备课");
Objectinvoke=method.invoke(target,args);
System.out.println("教师讲完课了");
returninvoke;
}
}
publicclassClient{
publicstaticvoidmain(String[]args){
 //创立方针方针
TeacherDaoteacherDao=newTeacherDao();
//创立署理方针,回来被署理的方针方针(必须强制类型转换)
TeacherDaoproxyInstance=(TeacherDao)newProxyFactory(teacherDao).getProxyInstance();
proxyInstance.teach();
}
}

署理形式的变体:防火墙署理、缓存署理、远程署理、同步署理

观察者形式

观察者形式:方针之间多对一依靠的一种规划方案,被依靠的方针为Subject依靠的方针为Observer,subject告诉Observer变化,比方这儿的奶站/气象局是subject,是1的一方。用户是Observer,是多的一方。

软件工程 | 设计模式Java版

①subject
registerObserver() 注册
removeObserver() 移除
notifyObservers() 告诉一切的注册的用户,根据不同需求,能够是更新数据,让用户来取,也可能是实施推送,看详细需求定。
②Observer
update() 接纳输入更新

软件工程 | 设计模式Java版

//接口, 让WeatherData 来完结【被观察者】 
public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();
}
//观察者接口,由观察者来完结
public interface Observer {
    public void update(float temperature, float pressure, float humidity);
}
//观察者的完结1
public class CurrentConditions implements Observer {
    // 温度,气压,湿度
    private float temperature;
    private float pressure;
    private float humidity;
    // 更新 天气情况,是由 WeatherData 来调用,我运用推送形式
    public void update(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }
    // 显现
    public void display() {
        System.out.println("***Today mTemperature: " + temperature + "***");
        System.out.println("***Today mPressure: " + pressure + "***");
        System.out.println("***Today mHumidity: " + humidity + "***");
    }
}
//观察者的完结2
public class BaiduSite implements Observer {
    // 温度,气压,湿度
    private float temperature;
    private float pressure;
    private float humidity;
    // 更新 天气情况,是由 WeatherData 来调用,我运用推送形式
    public void update(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }
    // 显现
    public void display() {
        System.out.println("===百度网站====");
        System.out.println("***百度网站 气温 : " + temperature + "***");
        System.out.println("***百度网站 气压: " + pressure + "***");
        System.out.println("***百度网站 湿度: " + humidity + "***");
    }
}
public class WeatherData implements Subject {
    private float temperatrue;
    private float pressure;
    private float humidity;
    //观察者集合
    private ArrayList<Observer> observers;
    //参加新的第三方
    public WeatherData() {
        observers = new ArrayList<Observer>();
    }
    public float getTemperature() {
        return temperatrue;
    }	
    public float getPressure() {
        return pressure;
    }
    public float getHumidity() {
        return humidity;
    }
    public void dataChange() {
        //调用 接入方的 update
        notifyObservers();
    }
    //当数据有更新时,就调用 setData
    public void setData(float temperature, float pressure, float humidity) {
        this.temperatrue = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        //调用dataChange, 将最新的信息 推送给 接入方 currentConditions
        dataChange();
    }
    //注册一个观察者
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }
    //移除一个观察者
    @Override
    public void removeObserver(Observer o) {
        if(observers.contains(o)) {
            observers.remove(o);
        }
    }
    //遍历一切的观察者,并告诉
    @Override
    public void notifyObservers() {
        for(int i = 0; i < observers.size(); i++) {
            observers.get(i).update(this.temperatrue, this.pressure, this.humidity);
        }
    }
}
public class Client {
    public static void main(String[] args) {
        // 创立一个WeatherData
        WeatherData weatherData = new WeatherData();
        // 创立观察者
        CurrentConditions currentConditions = new CurrentConditions();
        BaiduSite baiduSite = new BaiduSite();
        // 注册到weatherData
        weatherData.registerObserver(currentConditions);
        weatherData.registerObserver(baiduSite);
        // 测验
        System.out.println("告诉各个注册的观察者, 看看信息");
        weatherData.setData(10f, 100f, 30.3f);
        weatherData.removeObserver(currentConditions);
        // 测验
        System.out.println();
        System.out.println("告诉各个注册的观察者, 看看信息");
        weatherData.setData(10f, 100f, 30.3f);
    }
}
//成果
告诉各个注册的观察者, 看看信息
***Today mTemperature: 10.0***
***Today mPressure: 100.0***
***Today mHumidity: 30.3***
===百度网站====
***百度网站 气温 : 10.0***
***百度网站 气压: 100.0***
***百度网站 湿度: 30.3***
告诉各个注册的观察者, 看看信息
===百度网站====
***百度网站 气温 : 10.0***
***百度网站 气压: 100.0***
***百度网站 湿度: 30.3***

观察者形式规划后,会以集合的办法来管理用户(Observer)包含注册,移除和告诉
这样,咱们添加观察者(这儿能够了解成一个新的公告板),就不需求去修正核心类WeatherData不会修正代码,恪守了ocp准则。

参考资料

尚硅谷Java规划形式(图解+结构源码剖析)
规划形式的七大准则详解
java深仿制与浅仿制
规划形式-观察者形式