定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
public abstract class Duck{
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck(){}
pulbic void setFlyBehavior(FlyBehavior fb){flyBehavior = fb;}
pulbic void setQuackBehavior(QuackBehavior qb){quackBehavior = qb;}
public abstract void display();
public void performFly(){
flyBehavior.fly();
}
public void performQuack(){
quackBehavior.quack();
}
}
鸭子所做的一组行为,即一族算法,可以利用set方法被替换,这种方法就是组合,将两个类结合起来使用,使用组合建立系统具有很大的弹性,可以在运行时动态地改变行为。
解决算法行为类似时,过多if…else…问题。
共同实现一个接口,将算法封装成类,需要时进行替换。
在对象之间定义了一对多的依赖,这样依赖,当一个对象改变状态,依赖他的对象都会收到通知并自动更新。
public class WeatherData extends Observable{
private float temperature;
private float pressure;
public void measurementsChanged(){
setChanged();
notifyObservers();
}
public void setMeasurements(float temperature,float pressure){
this.temperature = temperature;
this.pressure = pressure;
measurementsChanged();
}
public float getTemperature(){...};
public float getPressure(){...};
}
public class ConditionDisplay implements Observer{
Observable observable;
private float temperature;
private float pressure;
public ConditionDisplay(Observable ob){
this.observable = ob;
observable.addObserver(this);
}
public void update(Observable obs, Object arg){
if(obs instanceof WeatherData){
WeatherData wd = (WeatherData) obs;
this.temperature = wd.getTemperature();
this.pressure = wd.getPressure();
display();
}
}
public void display(){
print(...);
}
}
利用JDK内置支持,首先”主题“继承Observable接口,“观察者”实现Observer接口。在Observable类中,先调用setChange()方法,标记状态改变,在调用notifyObservers()方法,方法中会调用它的观察者的update()方法,其中参数Object arg可决定”推“或”拉“数据。
一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
实现Observable和Observer接口,通过遍历注册的观察者对象数组,广播通知。
动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
public abstrack class Beverage{
String description = "Unknown Beverage";
public String get Description(){
return description;
}
public abstract double cost();
}
pulbic abstract class CondimentDecorator extends Beverage{
public abstract String get Description();
}
public class Espresso extends Beverage{
public Espresso(){
description = "Espresso";
}
public double cost(){
return 1.99;
}
}
public class HouseBlend extends Beverage{
public HouseBlend(){
description = "HouseBlend";
}
public double cost(){
return 0.89;
}
}
public class Mocha extends CondimentDecorator{
Beverage beverage;
public Mocha(Beverage beverage){
this.beverage = beverage;
}
pulbic String getDescription(){
return beverage.getDescription() + ", Mocha";
}
public double cost(){
return 0.2 + beverage.cost();
}
}
puvlic class CoffeeHouse{
public static void main(String args[]){
Beverage beverage = new Espresso();
Beverage decoratedBeverage = new Mocha(beverage);
print(decoratedBeverage.getDescription() + "$" +decoratedBeverage.cost());
}
}
保持类方法签名完整性的前提下,利用继承提供了额外的功能。我们需要有抽象组件(Beverage),具体组件(Espresso,HouseBlend),抽象装饰者(CondimentDecorator)以及具体修饰者(Mocha)。继承或实现接口的目的不是为了获得行为而是获得相同的类型。
防止单纯继承导致的子类膨胀问题。
通过继承和组合扩展父类。实现了对扩展开放对修改关闭。
工厂模式是Java中最常用的设计模式之一
简单工厂:不是工厂模式,只是OO编程习惯。
工厂方法模式: 定义了一个创建对象的接口,但由于子类决定要求实例化的类时哪一个。工厂方法让类把实例化推迟到子类。
抽象工厂模式: 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
public class SimplePizzaFactory{
public Pizza createPizza(String type){
Pizza pizza = nul;
if(type.equals("cheese")){
pizza = new CheesePizza();
}else if(type.equals("pepperoni")){
pizza = new PepperoniPizza();
}
return pizza;
}
}
public class PizzaStore{
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory){
this.factory = factory;
}
public Pizza orderPizza(String type){
Pizza pizza;
pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
简单工厂利用组合,通过接收的参数不同返回不同的对象负责具体类的实例化,但是又缺点拓展性差,不符合开闭原则,不修改代码就无法拓展。
public abstract class PizzaStore{
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
protected abstract Pizza createPizza(String type);
}
public class NyPizzaStore extends PizzaStore{
Pizza createPizza(String item){
if(item.equals("cheese")){
return new NYStyleCheesePizza();
}else if(item.equals("pepperoni")){
return new NYStylePepperoniPizza();
}else return null;
}
}
工厂方法模式中,PizzaStore称为创建者类,其将实例化责任转移到一个方法中即createPizza(String),这样可以将处理对象的行为交给子类负责,超类代码和子类对象常见代码解耦,同时拓展性增强,支持增加新工厂产品。
public interface PizzaIngredientFactory{
public Dough createDough();
public Cheese createCheese();
}
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{
public Dough createDough(){
return new ThinCrustDough();
}
public Cheese createCheese(){
return new ReggianoCheese();
}
}
public abstract class Pizza{
String name;
Dough dough;
Cheese cheese;
abstract void prepare();
void bake(){
print("bake")
}
//cut..box
}
public class CheesPizza extends Pizza{
PizzaIngredientFactory ingredientFactory;
public CheesPizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory = ingredientFactory;
}
void prepare(){
print("preparing");
dough = ingredientFactory.createDough();
cheese = ingredientFactory.createCheese();
}
}
引入抽象工厂,工厂方法使用类,而抽象工厂使用对象,通过对象的组合创建一个产品家族。抽象工厂定义了一个负责创建一族产品的接口,接口中每个方法都创建一个具体产品,并用子类实现具体的做法。因此抽象工厂也是利用工厂方法的思想实现的。
工厂方法 | 抽象工厂 | |
---|---|---|
实现原理 | 利用继承 | 利用对象组合 |
扩展能力 | 支持增加新产品 | 支持增加产品族 |
封装对象的创建。
将类的实例化延迟到子类中进行。
确保一个类只有一个实例,并提供全局访问点。
public class Singleton{
private static Singleton uniqueInstance;
private Singleton(){}
public static Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
用静态便令记录唯一一个实例,构造器声明为私有,禁止外部类调用构造器。
public class Singleton{
private volatile static Singleton uniqueInstance;
private Singleton(){}
public static Singleton getInstance(){
if(uniqueInstance == null){
synchronized(Singleton.class){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
保证一个类仅有一个实例。
判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
将请求封装成对象,这可以让你使用不同的请求,队列,或者日志请求来参数化其他对象。命令模式也可以支持撤销操作。
public interface Command{
public void execute();
public void undo();
}
public class LightOnCommand implements Command{
Light light;
public LightOnCommand(Light light){
this.light = light;
}
pulbic void execute(){
light.on();
}
public void undo(){
light.off();
}
}
public class LightOffCommand implements Command{
Light light;
public LightOffCommand(Light light){
this.light = light;
}
pulbic void execute(){
light.off();
}
public void undo(){
light.on();
}
}
利用preCommand变量记录前一个状态即可实现undo操作,多次撤销用栈记录即可,还可以设置宏命令。
在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
通过调用者调用接受者执行命令,顺序:调用者→命令→接受者。命令对象封装了接收者的一个或一组动作。
适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本不兼容的类可以合作无间。
外观模式:提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
public interface MediaPlayer {
public void play(String audioType, String fileName);
}
public interface AdvancedMediaPlayer {
public void playVlc(String fileName);
public void playMp4(String fileName);
}
public class VlcPlayer implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: "+ fileName);
}
@Override
public void playMp4(String fileName) {
//什么也不做
}
}
public class Mp4Player implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
//什么也不做
}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: "+ fileName);
}
}
public class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType){
if(audioType.equalsIgnoreCase("vlc") ){
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
advancedMusicPlayer.playVlc(fileName);
}else if(audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer.playMp4(fileName);
}
}
}
public class AudioPlayer implements MediaPlayer {
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
//播放 mp3 音乐文件的内置支持
if(audioType.equalsIgnoreCase("mp3")){
System.out.println("Playing mp3 file. Name: "+ fileName);
}
//mediaAdapter 提供了播放其他文件格式的支持
else if(audioType.equalsIgnoreCase("vlc")
|| audioType.equalsIgnoreCase("mp4")){
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
}
else{
System.out.println("Invalid media. "+
audioType + " format not supported");
}
}
}
public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}
public interface Shape {
void draw();
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Rectangle::draw()");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Square::draw()");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Circle::draw()");
}
}
public class ShapeMaker {
private Shape circle;
private Shape rectangle;
private Shape square;
public ShapeMaker() {
circle = new Circle();
rectangle = new Rectangle();
square = new Square();
}
public void drawCircle(){
circle.draw();
}
public void drawRectangle(){
rectangle.draw();
}
public void drawSquare(){
square.draw();
}
}
public class FacadePatternDemo {
public static void main(String[] args) {
ShapeMaker shapeMaker = new ShapeMaker();
shapeMaker.drawCircle();
shapeMaker.drawRectangle();
shapeMaker.drawSquare();
}
}
适配器:需要使用一个现有类但是其接口不符合需求时。
外观:需要简化并统一一个很大的接口时
适配器:Adapter实现target接口
外观:统一简化接口
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
public abstract class CaffeineBeverage{
public final void prepareRecipe(){
boilWater();
brew();
pourInCup();
addCondiments();//hook
}
abstract void brew();
void addCondiments(){
print("add noting.");
};
void boilWater(){
print("...");
}
void pourInCup(){
print("...");
}
}
public class Coffee extends CaffeineBeverage{
public void brew(){
print("Dripping Coffee through filter");
}
@Override
pulbic void addCondiments(){
print("add milk");
}
}
当子类必须提供算法的某个实现时就使用抽象方法,并且可以设置hook,钩子在抽象类中不做事或者只做默认的事情,子类可以选择实现钩子但是不强制。算法中个别步骤可以又不同的实现但是算法结构是不变的,为了防止改变模板,可以将模板方法声明为final。区分策略模式和模板方法模式,一个用组合一个用继承。工厂方法是模板方法的一个特殊版本。
一些方法通用,却在每一个子类都重新写了这一方法。
将通用算法抽象出来,具体操作可以转移到子类实现,封装不变的部分,扩展可变部分。
迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
组合模式:允许你将对象组合树形结构来表现“整体/部分”的层次结构。组合能让客户以一致的方法处理个别对象和对象组合。
public class BreakFastIterator implements Iterator {
MenuItem[] items;
int position = 0;
public BreakFastIterator(MenuItem[] items) {
this.items = items;
}
@Override
public boolean hasNext() {
if(position >= items.length || items[position] == null){
return false;
}else{
return true;
}
}
@Override
public Object next() {
MenuItem item = items[position];
position += 1;
return item;
}
@Override
public void remove() {
Iterator.super.remove();
}
@Override
public void forEachRemaining(Consumer action) {
Iterator.super.forEachRemaining(action);
}
}
public class BreakFastMenu implements Menu {
static final int MAX_ITEMS = 10;
MenuItem[] menuItems;
int numOfMenu = 0;
public BreakFastMenu(){
menuItems = new MenuItem[MAX_ITEMS];
addMenuItem("鸡蛋","1");
addMenuItem("蛋糕","5");
}
@Override
public void addMenuItem(String name,String price){
MenuItem item = new MenuItem(name,price);
if(numOfMenu > 10){
System.out.println("不加了");
}else menuItems[numOfMenu++] = item;
}
@Override
public Iterator createIterator() {
return new BreakFastIterator(menuItems);
}
}
public class Waiter {
Menu BreakFastMenu;
Menu DinnerMenu;
public Waiter(Menu breakFastMenu, Menu dinnerMenu) {
this.BreakFastMenu = breakFastMenu;
this.DinnerMenu = dinnerMenu;
}
public void printMenu(){
Iterator breakfastIterator = BreakFastMenu.createIterator();
Iterator dinnerIterator = DinnerMenu.createIterator();
System.out.println("------breakfast---------");
printMenu(breakfastIterator);
System.out.println("------dinner-------------");
printMenu(dinnerIterator);
}
private void printMenu(Iterator iterator) {
while(iterator.hasNext()){
MenuItem item = (MenuItem) iterator.next();
System.out.println(item.name + " $" + item.price);
}
}
}
这里用了jdk自带迭代器接口,思路类似与抽象工厂,把元素之间游走的责任交给迭代器,而不是聚合对象。Java5之后支持for(Object obj : collection)语句不用显式地创建迭代器对象。
public class Employee {
private String name;
private String dept;
private int salary;
private List<Employee> subordinates;
public Employee(String name,String dept, int sal) {
this.name = name;
this.dept = dept;
this.salary = sal;
subordinates = new ArrayList<Employee>();
}
public void add(Employee e) {
subordinates.add(e);
}
public void remove(Employee e) {
subordinates.remove(e);
}
public List<Employee> getSubordinates(){
return subordinates;
}
public String toString(){
return ("Employee :[ Name : "+ name
+", dept : "+ dept + ", salary :"
+ salary+" ]");
}
}
public class CompositePatternDemo {
public static void main(String[] args) {
Employee CEO = new Employee("John","CEO", 30000);
Employee headSales = new Employee("Robert","Head Sales", 20000);
Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
CEO.add(headSales);
CEO.add(headMarketing);
headSales.add(salesExecutive1);
headSales.add(salesExecutive2);
System.out.println(CEO);
for (Employee headEmployee : CEO.getSubordinates()) {
System.out.println(headEmployee);
for (Employee employee : headEmployee.getSubordinates()) {
System.out.println(employee);
}
}
}
}
组合模式与迭代器模式共同使用比较复杂,组合模式建立了任意复杂的树状图,迭代器提供通用接口,可以做到遍历组件内所有菜单项。在调用过程中,叶子节点可以使用空迭代器,它的hasNext()永远返回false。
迭代器模式:不同的方式来遍历整个整合对象。
组合模式:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
迭代器模式:实现Iterator接口。
组合模式:树枝和叶子实现统一接口,树枝内部组合该接口。
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
public interface State {
public void start(Context context);
public void stop(Context context);
}
public class StartState implements State {
Context context;
public StartState(Context context){
this.context = context;
}
public void start() {
print("you are in game.");
}
public void stop() {
System.out.println("stop the game.");
context.setState(context.getStopState());
}
public String toString(){
return "Start State";
}
}
public class StopState implements State {
Context context;
public StopState(Context context){
this.context = context;
}
public void start() {
System.out.println("start the game.");
context.setState(context.getStartState());
}
public void stop() {
System.out.println("you already stop the game.");
}
public String toString(){
return "Stop State";
}
}
public class Context {
private State startState;
private State stopState;
private State state = stopState;
public Context(){
startState = new startState(this);
stopState = new StopState(this);
}
public void start(){
state.start();
}
public void stop(){
state.stop();
}
public void setState(State state){
this.state = state;
}
public State getxxState(){//get每一种状态
return xxstate;
}
......
}
public class StatePatternDemo {
public static void main(String[] args) {
Context context = new Context();
context.start();
contex.stop();
}
}
将状态封装成类,虽然会造成类的增多但是暴露在外的类只有Context上下文,类似于策略模式,但是策略模式是被动改变行为,状态模式是随时间变化而主动在建立好的方案中改变行为,类图和策略模式一致但是具体实现和目的不同。
对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
将具体状态抽象成类,实现一个共同的State接口,在状态类内执行相关行为,执行过后按照设计改变状态。
为另一个对象提供一个替身或占位符以访问这个对象。
public interface State extends Serializable {
void start();
void stop();
}
public interface GameStationRemote extends Remote {
String getType() throws RemoteException;
String getLocation() throws RemoteException;
State getState() throws RemoteException;
void start() throws RemoteException;
void stop() throws RemoteException;
}
public class GameStation extends UnicastRemoteObject implements GameStationRemote {
private StartState startState;
private StopState stopState;
private String Type;
private String Location;
public State state = null;
public GameStation(String Type, String Location) throws RemoteException {
startState = new StartState(this);
stopState = new StopState(this);
this.Type = Type;
this.Location = Location;
state = stopState;
}
public void start(){state.start();}
public void stop(){state.stop();}
public String getLocation(){return Location;}
public String getType() {return Type;}
public StartState getStartState() {return startState;}
public StopState getStopState() {return stopState;}
public State getState() {return state;}
public void setState(State state) {this.state = state;}
public class GameStationMonitor {
GameStationRemote machine;
public GameStationMonitor(GameStationRemote machine){this.machine = machine;}
public void report() throws RemoteException {
System.out.println("-------------------------------------");
System.out.println("Type: "+ machine.getType());
System.out.println("Location "+ machine.getLocation());
System.out.println("State: "+ machine.getState());
System.out.println("-------------------------------------");
}
}
public class GameStationTest {
public static void main(String[] args) throws RemoteException, MalformedURLException {
LocateRegistry.createRegistry(1099);
GameStation gameStation = new GameStation("MARK1","HEULibrary");
Naming.rebind("MARK1/GameStation1",gameStation);
}
}
public class test {
public static void main(String[] args) throws RemoteException {
GameStationMonitor monitor = null;
GameStationRemote machine = null;
try{
machine = (GameStationRemote)
Naming.lookup("rmi://127.0.0.1:1099/MARK1/GameStation1");
monitor = new GameStationMonitor(machine);
}catch (Exception e){
e.printStackTrace();
}
monitor.report();
machine.start();
monitor.report();
}
}
远程代理可以由本地方法调用的对象,其行为转发到远程对象中。利用RMI,客户对象调用stub的方法,stub的方法通过网络Socket输出流运给skeleton然后找到服务对象上的真正的方法,返回结果过程相同。为实现RMI,首先需要制作远程接口扩展Remote,stub和实际的服务都实现此接口。rmic帮助产生stub和skeleton,然后注册服务,客户就可调用远程接口方法了。
public interface ImgIcon extends Icon {
ImageIcon setScale(int width);
}
public class ImageProxy implements ImgIcon{
ImageIcon imageIcon = null;
URL imageURL;
Thread retrievalThread;
boolean retrieval = false;
final int width = 480;
double scale = 1.0;
public ImageProxy(URL url) {this.imageURL = url;}
@Override
public ImageIcon setScale(int width) {
Image image = imageIcon.getImage();
scale = width * 1.0 / imageIcon.getIconWidth();
image = image.getScaledInstance(width, (int)(imageIcon.getIconHeight()*scale),Image.SCALE_SMOOTH);
imageIcon.setImage(image);
return imageIcon;
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
if(imageIcon != null){
imageIcon.paintIcon(c,g,x,y);
}else{
g.drawString("loading.....",200,300);
if(retrieval == false){
retrieval = true;
retrievalThread = new Thread(new Runnable() {
@Override
public void run() {
try{
imageIcon = new ImageIcon(imageURL,"CD cover");
imageIcon = setScale(width);
c.repaint();
}catch (Exception e){
e.printStackTrace();
}
}
});
retrievalThread.start();
}
}
}
@Override
public int getIconWidth() {
if(imageIcon == null){
return 800;
}else{
return imageIcon.getIconWidth();
}
}
@Override
public int getIconHeight() {
if(imageIcon == null){
return 600;
}else{
return imageIcon.getIconHeight();
}
}
}
public class ImageComponent extends JComponent {
ImgIcon icon;
@Override
public void paint(Graphics g) {
super.paint(g);
if(icon == null){
g.drawString("请选择",50,100);
}else{
int iconWidth = icon.getIconWidth();
int iconHeight = icon.getIconHeight();
int x = (this.getWidth() - iconWidth) / 2;
int y = (this.getHeight() - iconHeight) / 2;
icon.paintIcon(this,g,x,y);
}
}
public void setIcon(ImgIcon icon){
this.icon = icon;
}
}
public class cdFrame extends JFrame {
public static final int width = 800;
public static final int height = 600;
public JFrame frame;
public JMenuBar menuBar;
public JMenu menu;
public JMenuItem item;
public ImgIcon icon;
public ImageComponent imageComponent = new ImageComponent();
Map<String, URL> cdList;
public cdFrame(Map<String,URL> cdList){
this.cdList = cdList;
frame = new JFrame("CD Cover");
frame.setSize(width,height);
frame.setLayout(new BorderLayout());
frame.setResizable(false);
menuBar = new JMenuBar();
menu = new JMenu("My Favorite");
frame.setJMenuBar(menuBar);
menuBar.add(menu);
for(String cdName : cdList.keySet()){
item = new JMenuItem(cdName);
menu.add(item);
URL imgURL = cdList.get(cdName);
item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
icon = new ImageProxy(imgURL);
imageComponent.setIcon(icon);
frame.repaint();
}
});
}
frame.add(imageComponent,BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
public class main {
public static Map<String,URL> cdList;
public static void main(String[] args) throws MalformedURLException {
cdList = new HashMap<>();
cdList.put("cd1",new URL("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Falbum%2Ff713f3c2ccfe83b2f646e64332ac22717e59bf1b.png&refer=http%3A%2F%2Fi0.hdslb.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1638235277&t=5043696bf3a55fa600f7411892062b7f"));
cdList.put("cd2",new URL("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F8%2F57eb31eb0aca9.jpg%3Fdown&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1638235277&t=d5620eb449662be7daec8f574888a963"));
cdFrame frame = new cdFrame(cdList);
}
}
代理的目的是控制对象的访问,一般情况下会用工厂返回实例化的代理对象,因此客户是不知道使用的是代理还是真正的对象。虚拟代理控制访问实例化开销大的对象。结构上类似装饰者模式,但是目的不同,装饰者模式为对象加上行为,而代理控制访问。
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 {
private String name;
private String gender;
private String interests;
private int rating;
private int ratingCount = 0;
@Override
public String getName() {
return name;
}
@Override
public String getGender() {
return gender;
}
@Override
public String getInterests() {
return interests;
}
@Override
public int getHotOrNotRating() {
if(ratingCount == 0) return 0;
else return rating / ratingCount;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public void setGender(String gender) {
this.gender = gender;
}
@Override
public void setInterests(String interests) {
this.interests = interests;
}
@Override
public void setHotOrNotRating(int rating) {
this.rating += rating;
ratingCount++;
}
}
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 {
if(method.getName().startsWith("get")){
return method.invoke(person,args);
}else if(method.getName().equals("setHotOrNotRating")){
throw new IllegalAccessException();
}else if(method.getName().startsWith("set")){
return method.invoke(person,args);
}
return null;
}
}
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 {
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")){
throw new IllegalAccessException();
}
return null;
}
}
public class Test {
PersonBean ma;
public static void main(String[] args) {
Test test = new Test();
test.init();
test.drive();
}
private void init() {
ma = new PersonBeanImpl();
ma.setName("maRuncheng");
ma.setGender("man");
ma.setInterests("java");
ma.setHotOrNotRating(8);
}
public void drive(){
PersonBean ownerProxy = getOwnerProxy(ma);
System.out.println("Name is " + ownerProxy.getName());
ownerProxy.setInterests("c++");
System.out.println("change he mind to " + ownerProxy.getInterests());
try{
ownerProxy.setHotOrNotRating(10);
}catch (Exception e){
System.out.println("you can't rating yourself");
}
System.out.println("Rating is " + ownerProxy.getHotOrNotRating());
System.out.println("========================================");
PersonBean nonOwnerProxy = getNonOwnerProxy(ma);
System.out.println("Name is " + ownerProxy.getName());
try{
nonOwnerProxy.setInterests("c++");
}catch (Exception e){
System.out.println("you can't change his interest");
}
System.out.println("ma still like " + ownerProxy.getInterests());
nonOwnerProxy.setHotOrNotRating(10);
System.out.println("Now,rating increase to " + ownerProxy.getHotOrNotRating());
}
public static PersonBean getOwnerProxy(PersonBean person){
return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new OwnerInvocationHandler(person));
}
public static PersonBean getNonOwnerProxy(PersonBean person){
return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new nonOwnerInvocationHandler(person));
}
}
提供InvocationHandler实现invoke方法,实际Subject的方法就由InvocationHandler控制访问。InvocationHandler是一个帮助Proxy的类,proxy将调用转发交给它处理,Proxy本身又静态方法Proxy.newProxyInstance动态创建。另外,使用jdk动态代理的Subject必须有接口。
控制希望访问的类。
增加代理层。
复合模式结合两个或以上的模式,组成一个解决方案,解决一再发生的一般性问题。