1.接口:
适配器模式:以前看大话设计模式的时候也接触过适配器模式,当时感觉只是停留在表面的理解上,今天看了接口这一章,在具体的场景中提出来的,感觉确实不一样。首先把代码拿上来吧:
package mindview;
public class AdapterPattern {
public static void main(String[] args) {
String str = "abcdef";
TransferString ts = new TransferString();
String result = AdapterPattern.process(new TransferAdapter(ts), str);
System.out.println(result);
}
public static String process(Processer p, String str){
return p.process(str);
}
}
interface Processer{
public String process(String str);
}
class TransferAdapter implements Processer{
Transfer transfer;
public TransferAdapter(Transfer transfer) {
this.transfer = transfer;
}
@Override
public String process(String str) {
return transfer.process(str);
}
}
class Transfer{
public String process(String str){return null;}
}
class TransferString extends Transfer{
public String process(String str){
char[] chs = str.toCharArray();
for(int i = 0; i < chs.length && i+1 < chs.length; i += 2){
char tmp = chs[i];
chs[i] = chs[i+1];
chs[i+1] = tmp;
}
return new String(chs);
}
}
这个程序是第9章的练习题11,请忽略将字符串中每一对字符进行交换的算法,不知道是不是对的,理解能力和算法能力都有待提高~~我们这边只是看一下程序的整体结构,在主类AdapterPattern中有一个process方法,里面有两个参数,一个是Processer接口类型 ,一个是需要被转换的字符串,这样,这个process方法就只能处理从Processer接口继承下来的类了,现在我们新加了一个Transfer系列的类,它就无法处理;因此,我们就添加了一个同样实现了Processer接口的TransferAdapter类来适配Transfer系列的类,这样就可以把Transfer转换为Processer了。
使用接口的核心原因:为了能够向上转型为多个基类型(以及由此而来的灵活性)。
接口使用的经典案例:工厂方法设计模式:实例(第九章练习题18)
package mindview;
public class FactoryPattern {
public static void main(String[] args) {
useCycle(new UnicycleFactory());
useCycle(new BicycleFactory());
useCycle(new TricycleFactory());
}
public static void useCycle(CycleFactory factory){
factory.getCycle().move();
}
}
interface Cycle{
public void move();
}
class Unicycle implements Cycle{
@Override
public void move() {
System.out.println("Unicycle move.");
}
}
class Bicycle implements Cycle{
@Override
public void move() {
System.out.println("Bicycle move.");
}
}
class Tricycle implements Cycle{
@Override
public void move() {
System.out.println("Tricycle move.");
}
}
interface CycleFactory{
Cycle getCycle();
}
class UnicycleFactory implements CycleFactory{
@Override
public Cycle getCycle() {
return new Unicycle();
}
}
class BicycleFactory implements CycleFactory{
@Override
public Cycle getCycle() {
return new Bicycle();
}
}
class TricycleFactory implements CycleFactory{
@Override
public Cycle getCycle() {
return new Tricycle();
}
}
匿名内部类版本的工厂方法:
package com.mindview.test;
public class Factories {
public static void main(String[] args) {
serviceConsumer(Implementation1.factory);
serviceConsumer(Implementation2.factory);
}/**OutPut:
Implementation1.method1()
Implementation1.method2()
Implementation2.method1()
Implementation2.method2()
*///~
public static void serviceConsumer(ServiceFactory fact){
Service service = fact.getService();
service.method1();
service.method2();
}
}
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Implementation1 implements Service{
private Implementation1() {
}
@Override
public void method1() {
System.out.println("Implementation1.method1()");
}
@Override
public void method2() {
System.out.println("Implementation1.method2()");
}
public static ServiceFactory factory = new ServiceFactory() {
@Override
public Service getService() {
return new Implementation1();
}
};
}
class Implementation2 implements Service{
private Implementation2() {
}
@Override
public void method1() {
System.out.println("Implementation2.method1()");
}
@Override
public void method2() {
System.out.println("Implementation2.method2()");
}
public static ServiceFactory factory = new ServiceFactory() {
@Override
public Service getService() {
return new Implementation2();
}
};
}
闭包与回调:
闭包是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域,通过这个定义可以看出内部类是面向对象的闭包,因为他不仅包含外围类的信息,还自动拥有一个指向此外围类对象的引用,在此作用域内。内部类有权操作所有的成员,包括private成员。
通过JavaScript代码比较容易理解:一个外部的函数里面声明了一个内部的函数,内部函数可以访问外部函数中的局部变量、传入的参数和其他内部函数,当这个内部函数可以被外部函数之外的地方引用时,就形成了一个闭包。这个时候,即便外部函数已经执行完成,该内部函数仍然可以被执行,并且其中所用到的函数的局部变量、传入的参数等仍然保留外部函数执行结束时的值,代码示例如下:
function Outer(){
var i=0;
function Inner(){
alert(++i);
}
return Inner;
}
var inner = Outer();
inner();
JavaScript的闭包是面向函数的,而java的闭包则是面向对象的,Java是通过内部类来实现闭包的,因为内部类可以访问到外围类的的所有成员,包括private的成员,因此在外围类中提供一个内部类的应用给外面的类或方法,这样就是一个闭包了,代码如下:
package mindview.closure;
public class Callbacks {
public static void main(String[] args) {
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
MyIncrement.f(c2);
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallbackReference());
caller1.go();
caller1.go();
caller2.go();
caller2.go();
}
}/**Output:
Other operation
1
1
2
Other operation
2
Other operation
3
*/
interface Incrementable{
void increment();
}
class Callee1 implements Incrementable{
private int i = 0;
@Override
public void increment() {
i++;
System.out.println(i);
}
}
class MyIncrement{
public void increment(){
System.out.println("Other operation");
}
static void f(MyIncrement mi){
mi.increment();
}
}
class Callee2 extends MyIncrement{
private int i = 0;
public void increment(){
super.increment();
i++;
System.out.println(i);
}
private class Closure implements Incrementable{
@Override
public void increment() {
Callee2.this.increment();
}
}
Incrementable getCallbackReference(){
return new Closure();
}
}
class Caller{
private Incrementable callbackReference;
Caller(Incrementable cbh){
callbackReference = cbh;
}
void go(){
callbackReference.increment();
}
}
通过内部类提供闭包的功能是优良的解决方案,它比指针更灵活、更安全。
编程上来说,一般使用一个库或类时,是你主动调用人家的API,这个叫Call,有的时候这样不能满足需要,需要你注册(注入)你自己的程序(比如一个对象),然后让人家在合适的时候来调用你,这叫Callback。设计模式中的Observer就是例子:所有的观察者都需要向自己关心的主题Observable注册,然后主题在适当时机(主题类对象的属性发生变化时)通知所有订阅它的观察者并更新,其中观察者都实现了一个统一的Observer接口中的Update方法。
回调实质上是指一个类尽管实际上实现了某种功能,但是没有直接提供相应的接口,客户类可以通过这个类的内部类的接口来获得这种功能。而这个内部类本身并没有提供真正的实现,仅仅调用外部类的实现。可见,回调充分发挥了内部类所具有的访问外部类的实现细节的优势。
上面代码中Caller类中的go方法就是对callbackReference中increment()方法的一个回调。