The Principles of Good Programming
Occam's Razor
"When you have two competing solutions to the same problem, the simpler one is the better."
SOLID - Robert C. Martin
Single Responsibility Principle: A class should have only a single reason to change.
Open-Closed Principle: A class should be open for extension and closed for modification. This is attributed to Bertrand Meyer.
Liskov Substitution Principle: This was created by Barbara Liskov, and she says a class should be replaceable by others that extend that class.
Interface Segregation Principle: A few specific interfaces are preferable than one general-purpose interface.
Dependency Inversion Principle: A class should depend on abstraction instead of implementation. This means that class dependencies must be focused on what is done and forget about how it is done.
http://www.baeldung.com/java-strategy-pattern
https://dzone.com/articles/strategy-pattern-using-lambda
https://jaxenter.com/patterns-java-8-lambdas-127635.html
Spring framework is often the target of a gazillion jokes just for having a class named SimpleBeanFactoryAwareAspectInstanceFactory, even if the name is actually well chosen: You’ll get a factory that produces instances of aspects by using another factory.
https://www.linkedin.com/pulse/welcome-factory-pattern-using-lambda-expressions-java-saral-saxena/
http://www.jiffle.net/blog/2017/04/02/the-factory-pattern-using-java-8-lambda-evolved/
https://dzone.com/articles/factory-pattern-using-lambda-expression-in-java-8
Create a Factory to generate an object of your concrete classes based on given information.
But this technique doesn’t scale very well if the factory method getShape
needs to take multiple arguments to pass on to the Shape constructors! You’d have to provide
a different functional interface than a simple Supplier.
https://dzone.com/articles/template-method-pattern-using
https://www.voxxed.com/2016/04/gang-four-patterns-functional-light-part-1/
https://www.voxxed.com/2016/05/gang-four-patterns-functional-light-part-2/
https://www.voxxed.com/2016/05/gang-four-patterns-functional-light-part-3/
https://www.voxxed.com/2016/05/gang-four-patterns-functional-light-part-4/
The Interpreter pattern is commonly used when it is required to evaluate expressions written in a specific formalism.
http://colobu.com/2014/09/05/design-pattern-cheatsheet/
1、代理模式—在AOP和remoting中被用的比较多。
2、单例模式—在spring配置文件中定义的bean默认为单例模式。
3、模板方法—用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
4、前端控制器—Spring提供了DispatcherServlet来对请求进行分发。
5、视图帮助(View Helper )—Spring提供了一系列的JSP标签,高效宏来辅助将分散的代码整合在视图里。
6、依赖注入—贯穿于BeanFactory / ApplicationContext接口的核心理念。
7、工厂模式—BeanFactory用来创建对象的实例。
DRY - Don’t repeat yourself
Abstraction Principle - Related to DRY is the abstraction principle “Each significant piece of functionality in a program should be implemented in just one place in the source code.”http://en.wikipedia.org/wiki/Abstraction_principle_(programming)
KISS (Keep it simple, stupid!) - Simplicity (and avoiding complexity) should always be a key goal. Simple code takes less time to write, has fewer bugs, and is easier to modify.http://en.wikipedia.org/wiki/KISS_principle
Avoid Creating a YAGNI (You aren’t going to need it) - You should try not to add functionality until you need it. http://en.wikipedia.org/wiki/YAGNI
Do the simplest thing that could possibly work - A good question to ask one’s self when programming is “What is the simplest thing that could possibly work?” This helps keep us on the path towards simplicity in the design. http://c2.com/xp/DoTheSimplestThingThatCouldPossiblyWork.html
Don’t make me think - This is actually the title of a book by Steve Krug on web usability that is also relevant in programming. The point is that code should be easily read and understood with a minimum of effort required. If code requires too much thinking from an observer to understand, then it can probably stand to be simplifiedhttp://www.sensible.com/dmmt.html
Open/Closed Principle - Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification. In other words, don't write classes that people can modify, write classes that people can extend. http://en.wikipedia.org/wiki/Open_Closed_Principle
Write Code for the Maintainer - Almost any code that is worth writing is worth maintaining in the future, either by you or by someone else. The future you who has to maintain code often remembers as much of the code, as a complete stranger, so you might as well always write for someone else. A memorable way to remember this is “Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live.” http://c2.com/cgi/wiki?CodeForTheMaintainer
Principle of least astonishment - The principle of least astonishment is usually referenced in regards to the user interface, but the same principle applies to written code. Code should surprise the reader as little as possible. The means following standard conventions, code should do what the comments and name suggest, and potentially surprising side effects should be avoided as much as possible. http://en.wikipedia.org/wiki/Principle_of_least_astonishment
Single Responsibility Principle - A component of code (e.g. class or function) should perform a single well defined task. http://en.wikipedia.org/wiki/Single_responsibility_principle
Minimize Coupling - Any section of code (code block, function, class, etc) should minimize the dependencies on other areas of code. This is achieved by using shared variables as little as possible. “Low coupling is often a sign of a well-structured computer system and a good design, and when combined with high cohesion, supports the general goals of high readability and maintainability” http://en.wikipedia.org/wiki/Coupling_(computer_programming)
Maximize Cohesion - Code that has similar functionality should be found within the same component. http://en.wikipedia.org/wiki/Cohesion_(computer_science)
Hide Implementation Details - Hiding implementation details allows change to the implementation of a code component while minimally affecting any other modules that use that component. http://en.wikipedia.org/wiki/Information_Hiding
Law of Demeter - Code components should only communicate with their direct relations (e.g. classes that they inherit from, objects that they contain, objects passed by argument, etc.)http://en.wikipedia.org/wiki/Law_of_Demeter
Avoid Premature Optimization - Don’t even think about optimization unless your code is working, but slower than you want. Only then should you start thinking about optimizing, and then only with the aid of empirical data. "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil" - Donald Knuth.http://en.wikipedia.org/wiki/Program_optimization
Code Reuse is Good - Not very pithy, but as good a principle as any other. Reusing code improves code reliability and decrease development time.http://en.wikipedia.org/wiki/Code_reuse
Separation of Concerns - Different areas of functionality should be managed by distinct and minimally overlapping modules of code. http://en.wikipedia.org/wiki/Separation_of_concerns
Embrace Change -
Occam's Razor
"When you have two competing solutions to the same problem, the simpler one is the better."
SOLID - Robert C. Martin
Single Responsibility Principle: A class should have only a single reason to change.
Open-Closed Principle: A class should be open for extension and closed for modification. This is attributed to Bertrand Meyer.
Liskov Substitution Principle: This was created by Barbara Liskov, and she says a class should be replaceable by others that extend that class.
Interface Segregation Principle: A few specific interfaces are preferable than one general-purpose interface.
Dependency Inversion Principle: A class should depend on abstraction instead of implementation. This means that class dependencies must be focused on what is done and forget about how it is done.
http://www.baeldung.com/java-strategy-pattern
This advantage becomes more apparent when we want to declare even more Discounters in line:
1
2
3
4
5
| List<Discounter> discounters = newArrayList( amount -> amount.multiply(BigDecimal.valueOf( 0.9 )), amount -> amount.multiply(BigDecimal.valueOf( 0.8 )), amount -> amount.multiply(BigDecimal.valueOf( 0.5 )) ); |
When we want to define lots of Discounters, we can declare them statically all in one place. Java 8 even lets us define static methods in interfaces if we want to.
So instead of choosing between concrete classes or anonymous inner types, let’s try creating lambdas all in a single class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| public interface Discounter { BigDecimal applyDiscount(BigDecimal amount); static Discounter christmasDiscounter() { return amount -> amount.multiply(BigDecimal.valueOf( 0.9 )); } static Discounter newYearDiscounter() { return amount -> amount.multiply(BigDecimal.valueOf( 0.8 )); } static Discounter easterDiscounter() { return amount -> amount.multiply(BigDecimal.valueOf( 0.5 )); } }
|
3.2. Leveraging Function Composition
Let’s modify our Discounter interface so it extends the UnaryOperator interface, and then add a combine() method:
1
2
3
4
5
| public interface Discounter extends UnaryOperator<BigDecimal> { default Discounter combine(Discounter after) { return value -> after.apply( this .apply(value)); } } |
Essentially, we are refactoring our Discounter and leveraging a fact that applying a discount is a function that converts a BigDecimal instance into another BigDecimal instance, allowing us to access predefined methods. As the UnaryOperator comes with an apply() method, we can just replace applyDiscount with it.
Now, Let’s try applying multiple Discounters cumulatively to an amount. We will do this by using the functional reduce() and our combine():
1
2
3
4
5
| Discounter combinedDiscounter = discounters .stream() .reduce(v -> v, Discounter::combine); combinedDiscounter.apply(...); |
Pay special attention to the first reduce argument. When no discounts provided, we need to return the unchanged value. This can be achieved by providing an identity function as the default discounter.
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
List<Strategy> strategies = Arrays.asList( () -> {System.out.println("Perform task a day before deadline!");}, () -> {System.out.println("Perform task now!");} ); strategies.forEach((elem) -> elem.performTask());
List<Computation<Integer>> computations = Arrays.asList( (n, m)-> { return n+m; }, (n, m)-> { return n*m; }, (n, m)-> { return n-m; } ); computations.forEach((comp) -> System.out.println(comp.compute(10, 4))); }
https://jaxenter.com/patterns-java-8-lambdas-127635.html
Spring framework is often the target of a gazillion jokes just for having a class named SimpleBeanFactoryAwareAspectInstanceFactory, even if the name is actually well chosen: You’ll get a factory that produces instances of aspects by using another factory.
final
Supplier<Computation> slowFactory = () -> n -> {
long
rv = 0L;
for
(
long
i =
1
; i <= n; ++i) {
rv += i;
}
return
rv;
};
final
Supplier<Computation> gaussFactory = () -> n -> (n * (n+
1
))/
2
;
System.out.println(slowFactory.get().sum1To(
100
));
System.out.println(gaussFactory.get().sum1To(
100
));
Builders are often used together with fluent APIs or small, domain specific languages (DSLs) to create immutable objects without “telescoping” constructors (a telescoping constructor occurs when the increase of object constructor parameter combination leads to an exponential list of overloaded constructors).
The builder pattern is often used to configure things. Configuration often depends on a well-defined order of steps. The ideal implementation of a builder for me consists of a readable API, respecting the order of steps and resulting in an immutable object. Also, the builder used should be used only for one purpose.
http://www.jiffle.net/blog/2017/04/02/the-factory-pattern-using-java-8-lambda-evolved/
public class ShapeFactory {
@RequiredArgsConstructor
@Getter( AccessLevel.PRIVATE)
public static enum ShapeType {
CIRCLE( Circle::new),
RECTANGLE( Rectangle::new);
private final Supplier<Shape> constructor;
}
public static Shape createShape( ShapeType type) {
return type.getConstructor().get();
}
}
public class ShapeFactory {
@RequiredArgsConstructor
@Getter( AccessLevel.PRIVATE)
public static enum ShapeType {
CIRCLE( (c, t) -> new Circle( c, t)),
RECTANGLE( (c, t) -> new Rectangle( c, t));
private final ShapeConstructor constructor;
}
@FunctionalInterface
private interface ShapeConstructor {
Shape create( Color colour, int thickness);
}
public static Shape createShape( ShapeType type, Color colour, int thickness) {
return type.getConstructor().create( colour, thickness);
}
}
To me, this is where this gets really interesting. One of the main reasons to use the factory pattern is to decouple the points where the factory type is selected and where the instances are created. Ideally what we’d like to do is to construct the right type of factory in one part of the code, and then invoke the construction with parameters within a service that uses it.
We can do that here by changing the static factory method to return a lambda that constructs the instance. Conveniently, that is exactly the function signature that we already use in the enums.
This allows us to move the functional interface to the top-level class (since static methods are supported in Java 8). That static method also now becomes trivial, as it merely delegates to the getter in the relevant enum.
@FunctionalInterface
public interface ShapeFactory {
@RequiredArgsConstructor
@Getter( AccessLevel.PRIVATE)
public static enum ShapeType {
CIRCLE( (c, t) -> new Circle( c, t)),
RECTANGLE( (c, t) -> new Rectangle( c, t));
private final ShapeFactory constructor;
}
Shape create( Color colour, int thickness);
static ShapeFactory createFactory( ShapeType type) {
return type.getConstructor();
}
}
Create a Factory to generate an object of your concrete classes based on given information.
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
}
return null;
}
In Java 8, we can refer to constructors just like we refer to methods, by using
method references. For example, here’s how to refer to the Circle constructor:
method references. For example, here’s how to refer to the Circle constructor:
public class ShapeFactory {
final static Map<String, Supplier<Shape>> map = new HashMap<>();
static {
map.put("CIRCLE", Circle::new);
map.put("RECTANGLE", Rectangle::new);
}
public Shape getShape(String shapeType){
Supplier<Shape> shape = map.get(shapeType.toUpperCase());
if(shape != null) {
return shape.get();
}
throw new IllegalArgumentException("No such shape " + shapeType.toUpperCase());
}
}
needs to take multiple arguments to pass on to the Shape constructors! You’d have to provide
a different functional interface than a simple Supplier.
https://dzone.com/articles/template-method-pattern-using
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. TemplateMethod lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
Template Method pattern can be applied to above scenario by encapsulating the workflow system into an abstract class with few of the tasks out of the 4 tasks implemented. And leave the implementation of remaining tasks to the subclasses of the abstract class.
https://www.voxxed.com/2016/04/gang-four-patterns-functional-light-part-1/
public
static
void
publishText( String text, Predicate<String> filter, UnaryOperator<String> format) {
if
(filter.test( text )) {
System.out.println( format.apply( text ) );
}
}
public
static
void
withResource( Consumer<Resource> consumer) {
Resource resource =
new
Resource();
try
{
consumer.accept( resource );
}
finally
{
resource.dispose();
}
}
public
class
Observable {
private
final
Map<Object, Consumer<Object>> listeners =
new
ConcurrentHashMap<>();
public
void
register(Object key, Consumer<Object> listener) {
listeners.put(key, listener);
}
public
void
unregister(Object key) {
listeners.remove(key);
}
public
void
sendEvent(Object event) {
listeners.values().forEach( listener -> listener.accept( event ) );
}
}
The Decorator pattern allows to dynamically extend the functionality of an existing object by wrapping it with multiple nested layers. All these layers have to implement the same interface in order to allow their composition.
public
abstract
class
AbstractTaxDecorator
implements
SalaryCalculator {
private
final
SalaryCalculator salaryCalculator;
public
AbstractTaxDecorator( SalaryCalculator salaryCalculator ) {
this
.salaryCalculator = salaryCalculator;
}
protected
abstract
double
applyTax(
double
salary);
@Override
public
final
double
calculate(
double
gross) {
double
salary = salaryCalculator.calculate( gross );
return
applyTax( salary );
}
}
The advantage of this pattern is evidently in the fact that it allows to easily add and remove different decorators and then choose the taxes that should or shouldn't be applied for a certain salary calculation. The drawback, not considering the verbose implementation, is that the computation proceeds from the most internal calculator to the external ones and then the decorators have to be written in reverse order.
public
class
DefaultSalaryCalculator
implements
DoubleUnaryOperator {
@Override
public
double
applyAsDouble(
double
grossAnnual) {
return
grossAnnual /
12
;
}
}
the essence of the Decorator pattern. What it actually does it is offering a way to compose different computations, but functions composition is of course something that is far more natural in functional programming. It's almost surprising that we can achieve exactly the same result that costed us so many efforts using the Decorator pattern in a trivial way as it follows:
1
2
3
4
5
| double netSalary = new DefaultSalaryCalculator() .andThen( Taxes::generalTax ) .andThen( Taxes::regionalTax ) .andThen( Taxes::healthInsurance ) .applyAsDouble( 30000.00 ); |
public
static
double
calculate(
double
gross, DoubleUnaryOperator... fs) {
return
Stream.of( fs )
.reduce( DoubleUnaryOperator.identity(),
DoubleUnaryOperator::andThen )
.applyAsDouble( gross );
}
The Chain of Responsibility pattern
This pattern consists in creating a sequence of objects that are designed to process an input. Each object in the chain could, or could not, be able to process a specific input. If a processing object has been designed for the input at hand it will do so, otherwise it will pass the input down to the next object of the chain. If the last object of the chain also isn't able to process a given input, the chain will fail silently, or more commonly, will notify the user of the failure with an Exception
public static Optional<String> parseText(File file) { return file.getType() == File.Type.TEXT ? Optional.of( "Text file: " + file.getContent()) : Optional.empty(); }
|
String result = Stream.<Function<File, Optional<String>>>of(
// [1]
ChainOfRespLambda::parseText,
ChainOfRespLambda::parseAudio,
ChainOfRespLambda::parseVideo )
.map(f -> f.apply( file ))
// [2]
.filter( Optional::isPresent )
// [3]
.findFirst()
// [4]
.flatMap( Function.identity() )
// [5]
.orElseThrow( () ->
new
RuntimeException(
"Unknown file: "
+ file ) ) );
The Interpreter pattern is commonly used when it is required to evaluate expressions written in a specific formalism.
String expression =
"7 3 - 2 1 + *"
;
public
static
int
evaluate(String expression) {
Stack<Expression> stack =
new
Stack<>();
for
(String s : expression.split(
" "
)) {
if
(isOperator(s)) {
Expression right = stack.pop();
Expression left = stack.pop();
stack.push(getOperator(s, left, right));
}
else
{
Expression i =
new
Number(Integer.parseInt(s));
stack.push(i);
}
}
return
stack.pop().interpret();
}
static
Map<String, IntBinaryOperator> opMap =
new
HashMap<>();
static
{
opMap.put(
"+"
, (a, b) -> a + b);
opMap.put(
"*"
, (a, b) -> a * b);
opMap.put(
"-"
, (a, b) -> a - b);
}
public static int evaluate(String expression) { Stack<Integer> stack = new Stack<>(); for (String s : expression.split( " " )) { IntBinaryOperator op = opMap.get( s ); if (op != null ) { int right = stack.pop(); int left = stack.pop(); stack.push(op.applyAsInt( left, right )); } else { stack.push(Integer.parseInt(s)); } } return stack.pop(); }
the Visitor pattern is commonly used when it is required to add new operations to existing objects but it’s impossible (or not wanted for design reason) to modify the objects themselves and add the missing operations directly inside their implementation. To allow this each object of our domain must have a method accepting a Visitor and passing itself to the that Visitor and then have to implement an interface like the following. |
http://colobu.com/2014/09/05/design-pattern-cheatsheet/
JDK中设计模式的实现
Creational patterns
Abstract factory (recognizeable by creational methods returning the factory itself which in turn can be used to create another abstract/interface type)
javax.xml.parsers.DocumentBuilderFactory#newInstance()
javax.xml.transform.TransformerFactory#newInstance()
javax.xml.xpath.XPathFactory#newInstance()
Builder (recognizeable by creational methods returning the instance itself)
java.lang.StringBuilder#append()
(unsynchronized)java.lang.StringBuffer#append()
(synchronized)java.nio.ByteBuffer#put()
(also onCharBuffer
,ShortBuffer
,IntBuffer
,LongBuffer
,FloatBuffer
andDoubleBuffer
)javax.swing.GroupLayout.Group#addComponent()
- All implementations of
java.lang.Appendable
Factory method (recognizeable by creational methods returning an implementation of an abstract/interface type)
java.util.Calendar#getInstance()
java.util.ResourceBundle#getBundle()
java.text.NumberFormat#getInstance()
java.nio.charset.Charset#forName()
java.net.URLStreamHandlerFactory#createURLStreamHandler(String)
(Returns singleton object per protocol)
Prototype (recognizeable by creational methods returning a different instance of itself with the same properties)
java.lang.Object#clone()
(the class has to implementjava.lang.Cloneable
)
Singleton (recognizeable by creational methods returning the same instance (usually of itself) everytime)
Structural patterns
Adapter (recognizeable by creational methods taking an instance of different abstract/interface type and returning an implementation of own/another abstract/interface type which decorates/overrides the given instance)
java.util.Arrays#asList()
java.io.InputStreamReader(InputStream)
(returns aReader
)java.io.OutputStreamWriter(OutputStream)
(returns aWriter
)javax.xml.bind.annotation.adapters.XmlAdapter#marshal()
and#unmarshal()
Bridge (recognizeable by creational methods taking an instance of different abstract/interface type and returning an implementation of own abstract/interface type which delegates/uses the given instance)
- None comes to mind yet. A fictive example would be
new LinkedHashMap(LinkedHashSet<K>, List<V>)
which returns an unmodifiable linked map which doesn't clone the items, but uses them. Thejava.util.Collections#newSetFromMap()
andsingletonXXX()
methods however comes close.
Composite (recognizeable by behavioral methods taking an instance of same abstract/interface type into a tree structure)
java.awt.Container#add(Component)
(practically all over Swing thus)javax.faces.component.UIComponent#getChildren()
(practically all over JSF UI thus)
Decorator (recognizeable by creational methods taking an instance of same abstract/interface type which adds additional behaviour)
- All subclasses of
java.io.InputStream
,OutputStream
,Reader
andWriter
have a constructor taking an instance of same type. java.util.Collections
, thecheckedXXX()
,synchronizedXXX()
andunmodifiableXXX()
methods.javax.servlet.http.HttpServletRequestWrapper
andHttpServletResponseWrapper
Facade (recognizeable by behavioral methods which internally uses instances of different independent abstract/interface types)
javax.faces.context.FacesContext
, it internally uses among others the abstract/interface typesLifeCycle
,ViewHandler
,NavigationHandler
and many more without that the enduser has to worry about it (which are however overrideable by injection).javax.faces.context.ExternalContext
, which internally usesServletContext
,HttpSession
,HttpServletRequest
,HttpServletResponse
, etc.
Flyweight (recognizeable by creational methods returning a cached instance, a bit the "multiton" idea)
Proxy (recognizeable by creational methods which returns an implementation of given abstract/interface type which in turn delegates/uses a different implementation of given abstract/interface type)
java.lang.reflect.Proxy
java.rmi.*
, the whole API actually.
The Wikipedia example is IMHO a bit poor, lazy loading has actually completely nothing to do with the proxy pattern at all.
Behavioral patterns
Chain of responsibility (recognizeable by behavioral methods which (indirectly) invokes the same method in another implementation of same abstract/interface type in a queue)
Command (recognizeable by behavioral methods in an abstract/interface type which invokes a method in an implementation of a different abstract/interface type which has been encapsulated by the command implementation during its creation)
- All implementations of
java.lang.Runnable
- All implementations of
javax.swing.Action
Interpreter (recognizeable by behavioral methods returning a structurally different instance/type of the given instance/type; note that parsing/formatting is not part of the pattern, determining the pattern and how to apply it is)
java.util.Pattern
java.text.Normalizer
- All subclasses of
java.text.Format
- All subclasses of
javax.el.ELResolver
Iterator (recognizeable by behavioral methods sequentially returning instances of a different type from a queue)
- All implementations of
java.util.Iterator
(thus among others alsojava.util.Scanner
!). - All implementations of
java.util.Enumeration
Mediator (recognizeable by behavioral methods taking an instance of different abstract/interface type (usually using the command pattern) which delegates/uses the given instance)
java.util.Timer
(allscheduleXXX()
methods)java.util.concurrent.Executor#execute()
java.util.concurrent.ExecutorService
(theinvokeXXX()
andsubmit()
methods)java.util.concurrent.ScheduledExecutorService
(allscheduleXXX()
methods)java.lang.reflect.Method#invoke()
Memento (recognizeable by behavioral methods which internally changes the state of the whole instance)
java.util.Date
(the setter methods do that,Date
is internally represented by along
value)- All implementations of
java.io.Serializable
- All implementations of
javax.faces.component.StateHolder
Observer (or Publish/Subscribe) (recognizeable by behavioral methods which invokes a method on an instance of another abstract/interface type, depending on own state)
java.util.Observer
/java.util.Observable
(rarely used in real world though)- All implementations of
java.util.EventListener
(practically all over Swing thus) javax.servlet.http.HttpSessionBindingListener
javax.servlet.http.HttpSessionAttributeListener
javax.faces.event.PhaseListener
State (recognizeable by behavioral methods which changes its behaviour depending on the instance's state which can be controlled externally)
javax.faces.lifecycle.LifeCycle#execute()
(controlled byFacesServlet
, the behaviour is dependent on current phase (state) of JSF lifecycle)
Strategy (recognizeable by behavioral methods in an abstract/interface type which invokes a method in an implementation of a different abstract/interface type which has been passed-in as method argument into the strategy implementation)
java.util.Comparator#compare()
, executed by among othersCollections#sort()
.javax.servlet.http.HttpServlet
, theservice()
and alldoXXX()
methods takeHttpServletRequest
andHttpServletResponse
and the implementor has to process them (and not to get hold of them as instance variables!).javax.servlet.Filter#doFilter()
Template method (recognizeable by behavioral methods which already have a "default" behaviour definied by an abstract type)
- All non-abstract methods of
java.io.InputStream
,java.io.OutputStream
,java.io.Reader
andjava.io.Writer
. - All non-abstract methods of
java.util.AbstractList
,java.util.AbstractSet
andjava.util.AbstractMap
. javax.servlet.http.HttpServlet
, all thedoXXX()
methods by default sends a HTTP 405 "Method Not Allowed" error to the response. You're free to implement none or any of them.
Visitor (recognizeable by two different abstract/interface types which has methods definied which takes each theother abstract/interface type; the one actually calls the method of the other and the other executes the desired strategy on it)
javax.lang.model.element.AnnotationValue
andAnnotationValueVisitor
javax.lang.model.element.Element
andElementVisitor
javax.lang.model.type.TypeMirror
andTypeVisitor
1、代理模式—在AOP和remoting中被用的比较多。
2、单例模式—在spring配置文件中定义的bean默认为单例模式。
3、模板方法—用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
4、前端控制器—Spring提供了DispatcherServlet来对请求进行分发。
5、视图帮助(View Helper )—Spring提供了一系列的JSP标签,高效宏来辅助将分散的代码整合在视图里。
6、依赖注入—贯穿于BeanFactory / ApplicationContext接口的核心理念。
7、工厂模式—BeanFactory用来创建对象的实例。