观察者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
将一个系统分割成一系列相互协作的类 有一个很不好的副作用,那就是需要维护相关对象间的一致性。不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。
就是有点像老师要管理学生。
一个老师管理很多个学生。
明天上不上课,我要告诉所有学生。
恩
把老师抽象
//抽象统治者 一般用一个抽象类或者一个接口实现
abstract class Subject{
private List<Observer> observers = new ArrayList<Observer>();
//增加学生
public void Attach (Observer observer){
observers.add(observer);
}
//通知
public void Notify(){
for (Observer o:observers){
o.Update();
}
}
}
抽象学生
abstract class Observer{
public abstract void Update();
}
具体老师
class ConcreteSubject extends Subject{
private String subjectState;
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
}
}
具体学生
class ConcreteObserver extends Observer{
private String name;
private String observerState;
private ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject subject ,String name){
this.subject = subject;
this.name= name;
}
@Override
public void Update() {
// TODO Auto-generated method stub
observerState = subject.getSubjectState();
System.out.println("学生"+name+"的状态是"+observerState);
}
public ConcreteSubject getSubject() {
return subject;
}
public void setSubject(ConcreteSubject subject) {
this.subject = subject;
}
}
客户端
public static void main(String[] args) {
//同一个管理的类,增加要管理的人。然后统一设置属性。并显示
ConcreteSubject s = new ConcreteSubject();
s.Attach(new ConcreteObserver(s, "X"));
s.Attach(new ConcreteObserver(s, "Y"));
s.Attach(new ConcreteObserver(s, "Z"));
s.setSubjectState("放假");
s.Notify();
}
一个对象改变同时需要改变其他对,而且不知道有多少对象有待改变时
观察者模式所做的工作就是接触耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不影响另一边的变化。
用老师和学生的例子不是很好。恩,就是像今天的计划安排是根据天气的。我们的计划安排看到天气改变那也会变。里面的具体很多。都会改变。
抽象工厂模式
最简单的例子就是写项目的数据库更换的话。要改很多代码。
但是用抽象工厂模式不用那么麻烦了。
比如两个表中都有一个表User()
对这个表的操作抽象出来。因为有两种不同的数据库。操作相同,但是具体的写法细节不同。
//User表的抽象
interface IUser{
public void InsertBreakAction();
public void GetUser();
}
因为有两个数据库那么就实现两个
//实现操作User表的数据库
class SqlserverUser implements IUser{
@Override
public void InsertBreakAction() {
System.out.println("对User操作增加数据-----Sqlserver");
}
@Override
public void GetUser() {
System.out.println("对User操作获取数据-----Sqlserver");
}
}
//数据库Access
class AccessUser implements IUser{
@Override
public void InsertBreakAction() {
System.out.println("对User操作增加数据-----Access");
}
@Override
public void GetUser() {
System.out.println("对User操作获取数据-----Access");
}
}
要创建这两个不同的数据库对User的操作就是创建两个小工厂
先抽象出工厂
//定义抽象工厂
interface IFactory{
public IUser CreateUser();
}
创建两个小工厂
//针对两个数据库创建两个具体的小工厂
//sqlserver
class SqlServerFactory implements IFactory{
@Override
public IUser CreateUser() {
return new SqlserverUser();
}
}
//access
class AccessFactory implements IFactory{
@Override
public IUser CreateUser() {
// TODO Auto-generated method stub
return new AccessUser();
}
}
客户端
public static void main(String[] args) {
IFactory iFactory = new AccessFactory();
IUser iUser = iFactory.CreateUser();
iUser.InsertBreakAction();
iUser.GetUser();
}
抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类
可以用简单工厂替换工厂方法。就是说做一个判断。
什么数据库那么就创建什么数据库工厂。然后客户端只需要调用就可以了。
但是这样要增加数据库还是要改switch语句。
可以利用反射来实现
所谓反射
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
恩
举个栗子
定义个水果接口。子类有苹果和橘子。用到简单工厂的话。就要根据条件产生不同的子类。这就可以利用反射实现。
抽象水果
interface fruit{
public abstract void eat();
}
两种水果
class Apple implements fruit{
@Override
public void eat() {
System.out.println("Apple");
}
}
class Orange implements fruit{
@Override
public void eat() {
System.out.println("Orange");
}
}
利用反射的工厂
class Factory{
public static fruit getInstance(String clssname) {
fruit f = null;
try {
//Class.forName(传入需要的类名还有有包名).newInstance()
f = (fruit)Class.forName(clssname).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return f;
}
}
主方法创建
public static void main(String[] args) {
fruit f = Factory.getInstance("test.Orange");
f.eat();
}
恩,就是说这个创建什么数据库是我们说的算的,因为定义的是字符变量。编译的时候编译的是变量。没有写死。读取配置文件。是什么数据库就创建什么就可以了。
恩,反射理解的不是很到位。最近也在看核心技术。早日读完。
新手理解可能不是很到位,若有错误望指出。