前置知识
面向方针(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(统一建模语言),是一种用于软件系统剖析和规划的语言东西。【依靠、泛化(承继)、完结、关联、聚合与组合
】
规划形式
单例形式
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工厂等)
工厂形式
在软件开发中,当咱们会用到很多的创立某种、某类或许某批方针时,就会运用到工厂形式。
简略工厂形式
界说了一个创立方针的类
,由这个类来封装实例化方针的行为
(代码)。
//把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());
}
}
工厂办法形式
工厂办法形式规划方案:将披萨项目的实例化功用笼统成笼统办法,在不同的口味点餐子类中详细完结。
工厂办法形式:界说了一个创立方针的笼统办法
,由子类决定要实例化的类
。工厂办法形式将方针的实例化推迟到子类。
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(笼统工厂)和详细完结的工厂子类
。程序员能够根据创立方针类型运用对应的工厂子类。这样将单个的简略工厂类变成了工厂簇,更利于代码的维护和扩展。
//一个笼统工厂形式的笼统层(接口)
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接口的方针。它主要是用于创立一个杂乱的方针。它主要有两个效果,一是:阻隔了客户与方针的生产进程,二是:负责操控产品方针的生产进程。
//产品-->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署理(在内存动态的创立方针,而不需求完结接口)
。
静态署理
静态署理在运用时,需求界说接口或许父类,被署理方针(即方针方针)与署理方针一起完结相同的接口或许是承继相同父类。
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)
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编程中怎么挑选署理形式:
- 方针方针需求完结接口,用JDK署理
- 方针方针不需求完结接口,用cglib署理
cglib包的底层是经过运用字节码处理结构ASM
来转换字节码并生成新的类
。
asm.jar
asm-commons.jar
asm-tree.jar
cglib-2.2.jar
在内存中动态构建子类,留意署理的类不能为final
,不然报错java.lang.lllegalArgumentException
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,是多的一方。
①subjectregisterObserver() 注册
removeObserver() 移除
notifyObservers() 告诉
一切的注册的用户,根据不同需求,能够是更新数据,让用户来取,也可能是实施推送,看详细需求定。
②Observerupdate() 接纳输入更新
//接口, 让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深仿制与浅仿制
规划形式-观察者形式