`
jimode2013
  • 浏览: 39630 次
社区版块
存档分类
最新评论

thinking in java中出现的设计模式代码例子

 
阅读更多

代理模式

// : typeinf0/SimpleProxyDemo.j ava 
import static net.mindview.util.Print.*;

interface Interface {
	void doSomething();

	void somethingElse(String arg);
}

class RealObject implements Interface {
	public void doSomething() {
		print("doSomething");
	}

	public void somethingElse(String arg) {
		print("somethingElse " + arg);
	}
}

class SimpleProxy implements Interface {
	private Interface proxied;

	public SimpleProxy(Interface proxied) {
		this.proxied = proxied;
	}

	public void doSomething() {
		print("SimpleProxy doSomething");
		proxied.doSomething();
	}

	public void somethingElse(String arg) {
		print("SimpleProxy somethingElse " + arg);
		proxied.somethingElse(arg);
	}
}

public class SimpleProxyDemo {
	public static void consumer(Interface iface) {
		iface.doSomething();
		iface.somethingElse("bonobo");
	}

	public static void main(String[] args) {
		consumer(new RealObject());
		consumer(new SimpleProxy(new RealObject()));
	}
}

 动态代理模式

// : typeinfo/SimpleDynamicProxy.java 
import java.lang.reflect.*;

class DynamicProxyHandler implements InvocationHandler {
	private Object proxied;

	public DynamicProxyHandler(Object proxied) {
		this.proxied = proxied;
	}

	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("**** proxy: " + proxy.getClass() + ", method: "
				+ method + ", args: " + args);
		if (args != null)
			for (Object arg : args)
				System.out.println(" " + arg);
		return method.invoke(proxied, args);
	}
}

public class SimpleDynamicProxy {
	public static void consumer(Interface iface) {
		iface.doSomething();
		iface.somethingElse("bonobo");
	}

	public static void main(String[] args) {
		RealObject real = new RealObject();
		consumer(real);
		// Insert a proxy and call again:
		Interface proxy = (Interface) Proxy.newProxyInstance(
				Interface.class.getClassLoader(),
				new Class[] { Interface.class }, new DynamicProxyHandler(real));
		consumer(proxy);
	}
}

 

//: typeinfo/SelectingMethods.java 
// Looking for particular methods in a dynamic proxy. 
import java.lang.reflect.*;
import static net.mindview.util.Print.*;

class MethodSelector implements InvocationHandler {
	private Object proxied;

	public MethodSelector(Object proxied) {
		this.proxied = proxied;
	}

	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		if (method.getName().equals("interesting"))
			print("Proxy detected the interesting method");
		return method.invoke(proxied, args);
	}
}

interface SomeMethods {
	void boringl();

	void boring2();

	void interesting(String arg);

	void boring3();
}

class Implementation implements SomeMethods {
	public void boringl() {
		print("boringl");
	}

	public void boring2() {
		print("boring2");
	}

	public void interesting(String arg) {
		print("interesting " + arg);
	}

	public void boring3() {
		print("boring3");
	}
}

public class SelectingMethods {
	public static void main(String[] args) {
		SomeMethods proxy = (SomeMethods) Proxy.newProxyInstance(
				SomeMethods.class.getClassLoader(),
				new Class[] { SomeMethods.class }, new MethodSelector(
						new Implementation()));
		proxy.boringl();
		proxy.boring2();
		proxy.interesting("bonobo");
		proxy.boring3();
	}
}

 Strategy pattern

a special case of the Strategy pattern

Null Objects

The problem is that null has no behavior of its own except for producing a NullPointerException if you try to do anything with it. Sometimes it is useful to introduce the idea of a Null Objects that will accept messages for the object that it's "standing in" for, but will return values indicating that no "real" object is actually there. This way, you can assume that all objects are valid and you don't have to waste programming time checking for null (and reading the resulting code). 

Although it's fun to imagine a programming language that would automatically create Null Objects for you(Object C就是这样的), in practice it doesn't make sense to use them everywhere—sometimes checking for null is fine, and sometimes you can reasonably assume that you won't encounter null, and sometimes even detecting aberrations via NullPointerException is acceptable. The place where Null Objects seem to be most useful is "closer to the data," with objects that represent entities in the problem space. As a simple example,many systems will have a Person class, and there are situations in the code 

where you don't have an actual person (or you do, but you don't have all the information about that person yet), so traditionally you'd use a null reference and test for it. Instead, we can make a Null Object. But even though the Null Object will respond to all messages that the "real" object will respond to, you still need a way to test for nullness. The simplest way to do this is to create a tagging interface: 

 

// : net/mindview/uti1/Null.java 
package net.mindview.util ; 
public interface Null { }

 This allows instanceof to detect the Null Object, and more importantly,does not require you to add an isNull( ) method to all your classes (which would be, after all, just a different way of performing RTTI—why not use the built-in facility instead?). 

 

//: typeinfo/Person.java 
// A class with a Null Object. 
import net.mindview.util.*;

class Person {
	public final String first;
	public final String last;
	public final String address;

	// etc.
	
	
	public Person(String first, String last, String address) {
		this.first = first;
		this.last = last;
		this.address = address;
	}

	public String toString() {
		return "Person: " + first + " " + last + " " + address;
	}

	public static class NullPerson extends Person implements Null {
		private NullPerson() {
			super("None", "None", "None");
		}

		public String toString() {
			return "NullPerson";
		}
	}

	public static final Person NULL = new NullPerson();
} // /:-

In general, the Null Object will be a Singleton, so here it is created as a static final instance. This works because Person is immutable—you can only set the values in the constructor, and then read those values, but you can't modify them (because Strings themselves are inherently immutable). If you want to change a NullPerson, you can only replace it with a new Person object. Notice that you have the option of detecting the generic Null or the more specific NullPerson using instanceof, but with the Singleton approach you can also just use equals( ) or even == to compare to Person.NULL. 

Now suppose you're back in the high-flying days of Internet startups and you've been given a big pile of venture funding for your Amazing Idea. You'r ready to staff up, but while you're waiting for positions to be filled, you can use Person Null Objects as placeholders for each Position: 

//: typeinfo/Position.java 
public class Position {
	private String title;
	private Person person;

	public Position(String jobTitle, Person employee) {
		title = jobTitle;
		person = employee;
		if (person == null)
			person = Person.NULL;
	}

	public Position(String jobTitle) {
		title = jobTitle;
		person = Person.NULL;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String newTitle) {
		title = newTitle;
	}

	public Person getPerson() {
		return person;
	}

	public void setPerson(Person newPerson) {
		person = newPerson;
		if (person == null)
			person = Person.NULL;
	}

	public String toString() {
		return "Position: " + title + " " + person;
	}
} // /:-

With Position, we don't need to make a Null Object because the existence of Person.NULL implies a null Position (it's possible that, later, you'll discover the need to add an explicit Null Object for Position, but YAGNI(You Aren't Going to Need It) says to try "the simplest thing that could possibly work" for your first draft, and to wait until some aspect of the program requires you to add in the extra feature, rather than assuming it's necessary). 

The Staff class can now look for Null Objects when you are filling positions:

// : typeinfo/Staff.java 
import java.util.*;

public class Staff extends ArrayList<Position> {
	public void add(String title, Person person) {
		add(new Position(title, person));
	}

	public void add(String... titles) {
		for (String title : titles)
			add(new Position(title));
	}

	public Staff(String... titles) {
		add(titles);
	}

	public boolean positionAvailable(String title) {
		for (Position position : this)
			if (position.getTitle().equals(title)
					&& position.getPerson() == Person.NULL)
				return true;
		return false;
	}

	public void fillPosition(String title, Person hire) {
		for (Position position : this)
			if (position.getTitle().equals(title)
					&& position.getPerson() == Person.NULL) {
				position.setPerson(hire);
				return;
			}
		throw new RuntimeException("Position " + title + " not available");
	}

	public static void main(String[] args) {
		Staff staff = new Staff("President", "CTO", "Marketing Manager",
				"Product Manager", "Project Lead", "Software Engineer",
				"Software Engineer", "Software Engineer", "Software Engineer",
				"Test Engineer", "Technical Writer");
		staff.fillPosition("President", new Person("Me", "Last",
				"The Top, Lonely At"));
		staff.fillPosition("Project Lead", new Person("Janet", "Planner",
				"The Burbs"));
		if (staff.positionAvailable("Software Engineer"))
			staff.fillPosition("Software Engineer", new Person("Bob", "Coder",
					"Bright Light City"));
		System.out.println(staff);
	}
}

 Notice that you must still test for Null Objects in some places, which is not that different from checking for null, but in other places (such as toString( ) conversions, in this case), you don't have to perform extra tests;you can just assume that all object references are valid. 

If you are working with interfaces instead of concrete classes, it's possible to use a DynamicProxy to automatically create the Null Objects. Suppose we have a Robot interface that defines a name, model, and a List < Operation > that describes what the Robot is capable of doing. Operation contains a description and a command (it's a type of Command pattern): 

//: typeinfo/Operation.Java 
public interface Operation {
	String description();

	void command();
} // /:-

 You can access a Robot's services by calling operations( ):

// : typeinfo/Robot.java 
import java.util.*;
import net.mindview.util.*;

public interface Robot {
	String name();

	String model();

	List<Operation> operations();

	class Test {
		public static void test(Robot r) {
			if (r instanceof Null)
				System.out.println(" [Null Robot] ");
			System.out.println("Robot name: " + r.name());
			System.out.println("Robot model: " + r.model());
			for (Operation operation : r.operations()) {
				System.out.println(operation.description());
				operation.command();
			}
		}
	}
} // /:-

This also incorporates a nested class to perform tests. 

We can now create a Robot that removes snow: 

 

// : typeinfo/SnowRemovalRobot.Java 
import java.util.*;

public class SnowRemovalRobot implements Robot {
	private String name;

	public SnowRemovalRobot(String name) {
		this.name = name;
	}

	public String name() {
		return name;
	}

	public String model() {
		return "SnowBot Series 11";
	}

	public List<Operation> operations() {
		return Arrays.asList(new Operation() {
			public String description() {
				return name + " can shovel snow";
			}

			public void command() {
				System.out.println(name + " shoveling snow");
			}
		}, new Operation() {
			public String description() {
				return name + " can chip ice";
			}

			public void command() {
				System.out.println(name + " chipping ice");
			}
		}, new Operation() {
			public String description() {
				return name + " can clear the roof";
			}

			public void command() {
				System.out.println(name + " clearing roof");
			}
		});
	}

	public static void main(String[] args) {
		Robot.Test.test(new SnowRemovalRobot("Slusher"));
	}
}
There will presumably be many different types of Robot, and we'd like to have each Null Object do something special for each Robot type—in this case, incorporate information about the exact type of Robot the Null Object is standing for. This information will be captured by the dynamic proxy: 
//: typeinfo/NullRobot.java 
// Using a dynamic proxy to create a Null Object. 
import java.lang.reflect.*;
import java.util.*;
import net.mindview.util.*;

class NullRobotProxyHandler implements InvocationHandler {
	private String nullName;
	private Robot proxied = new NRobot();

	NullRobotProxyHandler(Class<? extends Robot> type) {
		nullName = type.getSimpleName() + " NullRobot";
	}

	private class NRobot implements Null, Robot {
		public String name() {
			return nullName;
		}

		public String model() {
			return nullName;
		}

		public List<Operation> operations() {
			return Collections.emptyList();
		}
	}

	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		return method.invoke(proxied, args);
	}
}

public class NullRobot {
	public static Robot newNullRobot(Class<? extends Robot> type) {
		return (Robot) Proxy.newProxyInstance(NullRobot.class.getClassLoader(),
				new Class[] { Null.class, Robot.class },
				new NullRobotProxyHandler(type));
	}

	public static void main(String[] args) {
		Robot[] bots = { new SnowRemovalRobot("SnowBee"),
				newNullRobot(SnowRemovalRobot.class) };
		for (Robot bot : bots)
			Robot.Test.test(bot);
	}
}
 Whenever you need a null Robot object, you just call newNullRobot( ),passing the type of Robot you want a proxy for. The proxy fulfills the requirements of the Robot and Null interfaces, and provides the specific name of the type that it proxies. 

Factory Method design pattern

 

 

// : generics/coffee/Coffee.Java 
package generics.coffee;

public class Coffee {
	private static long counter = 0;
	private final long id = counter++;

	public String toString() {
		return getClass().getSimpleName() + " " + id;
	}
} // /: -

 

//: generics/coffee/Latte.java
package generics.coffee; 
public class Latte extends Coffee {}

 

//: generics/coffee/Mocha.Java 
package generics.coffee; 
public class Mocha extends Coffee {} ///:-

 

 

 

 

//: generics/coffee/Cappuccino.java 
package generics.coffee; 
public class Cappuccino extends Coffee {} ///:-

 

 

 

 

//: generics/coffee/Americano.Java 
package generics.coffee; 
public class Americano extends Coffee {} 

 

//: generics/coffee/Breve.Java 
package generics.coffee; 
public class Breve extends Coffee {}

 

 

Now we can implement a Generator < Coffee > that produces random different types of Coffee objects: 

 

//: generics/coffee/CoffeeGenerator.java 
// Generate different types of Coffee: 
package generics.coffee;

import java.util.*;
import net.mindview.util.*;

public class CoffeeGenerator implements Generator<Coffee>, Iterable<Coffee> {
	private Class[] types = { Latte.class, Mocha.class, Cappuccino.class,
			Americano.class, Breve.class, };
	private static Random rand = new Random(47);

	public CoffeeGenerator() {
	}

	// For iteration:
	private int size = 0;

	public CoffeeGenerator(int sz) {
		size = sz;
	}

	public Coffee next() {
		try {
			return (Coffee) types[rand.nextInt(types.length)].newInstance();
			// Report programmer errors at run time:
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	class Coffeelterator implements Iterator<Coffee> {
		int count = size;

		public boolean hasNext() {
			return count > 0;
		}

		public Coffee next() {
			count--;
			return CoffeeGenerator.this.next();
		}

		public void remove() { // Not implemented
			throw new UnsupportedOperationException();
		}
	};

	public Iterator<Coffee> iterator() {
		return new Coffeelterator();
	}

	public static void main(String[] args) {
		CoffeeGenerator gen = new CoffeeGenerator();
		for (int i = 0; i < 5; i++)
			System.out.println(gen.next());
		for (Coffee c : new CoffeeGenerator(5))
			System.out.println(c);
	}
}

 

Here's a second implementation of Generator<T>, this time to produce Fibonacci numbers: 

package generics.coffee;

//: generics/Fibonacci.java 
// Generate a Fibonacci sequence, 
import net.mindview.util.*;

public class Fibonacci implements Generator<Integer> {
	private int count = 0;

	public Integer next() {
		return fib(count++);
	}

	private int fib(int n) {
		if (n < 2)
			return 1;
		return fib(n - 2) + fib(n - 1);
	}

	public static void main(String[] args) {
		Fibonacci gen = new Fibonacci();
		for (int i = 0; i < 18; i++)
			System.out.print(gen.next() + " ");
	}
} 

 

Adapters 

原本的实现:

package generics.coffee;

//: generics/Fibonacci.java 
// Generate a Fibonacci sequence, 
import net.mindview.util.*;

public class Fibonacci implements Generator<Integer> {
	private int count = 0;

	public Integer next() {
		return fib(count++);
	}

	private int fib(int n) {
		if (n < 2)
			return 1;
		return fib(n - 2) + fib(n - 1);
	}

	public static void main(String[] args) {
		Fibonacci gen = new Fibonacci();
		for (int i = 0; i < 18; i++)
			System.out.print(gen.next() + " ");
	}
} 

 

package generics.coffee;

//: generics/IterableFibonacci.java 
// Adapt the Fibonacci class to make it Iterable. 
import java.util.*;

public class IterableFibonacci extends Fibonacci implements Iterable<Integer> {
	private int n;

	public IterableFibonacci(int count) {
		n = count;
	}

	public Iterator<Integer> iterator() {
		return new Iterator<Integer>() {
			public boolean hasNext() {
				return n > 0;
			}

			public Integer next() {
				n--;
				return IterableFibonacci.this.next();
			}

			public void remove() { // Not implemented
				throw new UnsupportedOperationException();
			}
		};
	}

	public static void main(String[] args) {
		for (int i : new IterableFibonacci(18))
			System.out.print(i + " ");
	}
}

 

 

 

 

分享到:
评论

相关推荐

    Thinking in java 电子书

    12. **设计模式**:书中还讨论了多种设计模式,如工厂模式、单例模式、观察者模式等,这些都是软件设计中的通用解决方案,对于提升代码质量和可维护性至关重要。 通过深入学习《Thinking in Java》,读者不仅可以...

    thinking in java 源码

    13. **设计模式**:《Thinking in Java》也涵盖了常见的设计模式,如工厂模式、单例模式、观察者模式等。源码会展示如何在实际项目中应用这些模式。 通过对这些源码的阅读和实践,开发者不仅可以深化对Java语言的...

    thinking in java 第四版 源码

    源码是程序员与计算机交流的语言,通过阅读和分析《Thinking in Java》的源码,我们可以更直观地理解书中的编程思想和设计模式。第四版的源码反映了Java SE 5.0及之后的版本特性,如枚举类型、泛型、注解等,这些都...

    Thinking in Java Second Edition.doc

    特别值得一提的是,书中关于设计模式和良好编程实践的讨论,不仅帮助读者构建起良好的编程习惯,同时也提升了代码的质量和可维护性。 对于初学者而言,《Thinking in Java》第二版无疑是一本极佳的入门教材。它从...

    thinking in java&C++

    在《Thinking in Java》中,作者首先介绍了面向对象编程的基础,包括类、对象、封装、继承和多态等概念。书中的例子通常涉及实际问题,使读者能理解如何在实际开发中应用这些理论。接着,书中涵盖了集合框架、泛型、...

    THINKING IN JAVA

    11. **设计模式**:介绍了常见的设计模式,如工厂模式、单例模式、观察者模式等,并展示了它们在实际项目中的应用。 12. **单元测试**:教导如何使用JUnit进行代码测试,确保程序的正确性。 《Thinking in Java》...

    Thinking in Java 3th and 4th Edition+代码+答案

    《Thinking in Java》是Bruce Eckel的经典编程教材,它涵盖了Java语言的核心概念和技术,深受程序员和初学者喜爱。这本书分为第三版和第四版,每个版本都有其独特的知识点和更新内容。 第三版是针对Java 2 Platform...

    Thinking in Patterns with Java(include code)

    通过《Thinking.in.Patterns.with.Java》这个压缩包,你可以获得书中所有示例代码,这将是你实践和学习设计模式的宝贵资源。你可以逐个研究这些代码,理解它们如何体现和应用各种设计模式,也可以尝试修改这些代码,...

    Thinking in java 1

    3. **接口与抽象类**:理解Java中的接口如何实现多继承,以及抽象类在设计模式中的应用。 4. **集合框架**:涵盖ArrayList、LinkedList、HashMap、HashSet等集合类的使用,以及泛型的理解和应用。 5. **异常处理**...

    Thinking in Java 3rd Edition(英文版)

    12. **设计模式**:结合实际案例,阐述了一些常见的设计模式,如工厂模式、单例模式、观察者模式等,帮助读者提升代码的结构和质量。 压缩包中的"TIJ-3rd-edition-html"可能包含的是这本书的HTML格式版本,便于电子...

    java编程思想thinking in java

    以上只是《Java编程思想》中部分核心知识点的概述,实际书籍中涉及的内容更为丰富,包括网络编程、数据库连接、GUI编程、Swing、JDBC、设计模式等多个方面,是一本全面而深入的Java学习指南。通过阅读和实践书中的...

    thinking in java源代码

    通过深入学习和实践这些源代码,你不仅可以掌握Java语言的精髓,还能培养良好的编程习惯和设计模式,提升编程思维。对于初学者来说,这是一个极佳的自我学习平台,可以帮助你逐步成长为一名优秀的Java程序员。在阅读...

    thinking in java 4th

    书中的例子丰富多样,涵盖了从简单的数据结构到复杂的算法,从基本的类设计到高级的设计模式。此外,书中还强调了单元测试的重要性,教导读者如何使用JUnit进行测试驱动开发。 通过这个压缩包,你可以按照自己的...

    Thinking in Java 4th Edition.docx

    - **Anatoly Vorobey**(Technion University, Haifa, Israel)指出,《Thinking in Java》相较于其他Java书籍更为全面,包含了许多直接到位的例子和智能而非简化过的解释。 - **Joakim Ziegler**(FIXsysop)称赞其...

    thinking in java 4

    10. **设计模式**:《Thinking in Java》还涵盖了多种经典的设计模式,如工厂模式、单例模式、装饰者模式等,这些模式是解决常见问题的通用解决方案,对提升代码质量和可维护性至关重要。 总的来说,《Thinking in ...

    thinking in java 3rd

    12. **设计模式**:书中可能会介绍一些常见的设计模式,如工厂模式、单例模式、装饰器模式等,帮助读者理解如何在实际开发中提高代码质量。 《Thinking in Java》第三版的PDF版不仅包含了以上内容,还可能包含作者...

    Thinking In Java 4th

    - **面向对象编程的深度探索**:书中对面向对象设计模式和原则的深入探讨被许多读者高度赞扬。这种深度有助于开发者更好地理解和应用面向对象编程的思想。 - **实战案例的实用性**:本书中的实例和练习题被普遍认为...

    Thinking in Java(英)

    11. **设计模式**:作为程序员的通用智慧结晶,设计模式在《Thinking in Java》中也会有所涉及,比如单例模式、工厂模式、观察者模式等。 12. **测试**:包括JUnit框架和其他单元测试工具的使用,以及测试驱动开发...

    Thinking in Java, 3rd ed.

    《Thinking in Java》是Bruce Eckel的经典著作,第三版涵盖了Java编程语言的广泛主题,旨在帮助程序员深入理解Java的本质和哲学。这本书不仅讲解了语言的基础,还探讨了高级特性和设计模式,是学习和进阶Java开发的...

Global site tag (gtag.js) - Google Analytics