자바 프로 그래 밍 사상 독서 노트-범 형(4)

50622 단어 자바
15.15 혼합 형
혼합 형:여러 가지 유형 을 혼합 하 는 능력 으로 혼합 형 중의 모든 유형 을 나 타 낼 수 있 는 유형 을 만 듭 니 다.
15.15.1 C++의 혼 형
15.15.2 인터페이스 와 혼합
인터페이스 사용 시 혼합 효과 발생:
package com.mzm.chapter15;

import java.util.Date;

/**
 * 
 */
public class Mixins {

    public static void main(String[] args) {
        Mixin mixin1 = new Mixin(), mixin2 = new Mixin();
        mixin1.set("test string 1");
        mixin2.set("test string 2");
        System.out.println(mixin1.get() + " " + mixin1.getStamp() + " " + mixin1.getSerialNumber());
        System.out.println(mixin2.get() + " " + mixin2.getStamp() + " " + mixin2.getSerialNumber());
    }
}

interface TimeStamped {
    long getStamp();
}

class TimeStampedImp implements TimeStamped {

    private final long timeStamp;

    public TimeStampedImp() {
        timeStamp = new Date().getTime();
    }

    @Override
    public long getStamp() {
        return timeStamp;
    }
}

interface SerialNumbered {
    long getSerialNumber();
}

class SerialNumberImp implements SerialNumbered {

    private static long counter = 1;

    private final long serialNumber = counter++;

    @Override
    public long getSerialNumber() {
        return serialNumber;
    }
}

interface Basic {
    void set(String val);
    String get();
}

class BasicImp implements Basic {

    private String value;

    @Override
    public void set(String val) {
        value = val;
    }

    @Override
    public String get() {
        return value;
    }
}

/**
 *   TimeStamped, SerialNumbered    
 *     TimeStamped, SerialNumbered           
 *                      
 */
class Mixin extends BasicImp implements TimeStamped, SerialNumbered{

    private TimeStamped timeStamped = new TimeStampedImp();
    private SerialNumbered serialNumber = new SerialNumberImp();

    @Override
    public long getStamp() {
        return timeStamped.getStamp();
    }

    @Override
    public long getSerialNumber() {
        return serialNumber.getSerialNumber();
    }
}

본질은 프 록 시 모드 를 사용 하 는 것 입 니 다.모든 혼합 유형 은 목표 클래스 에 해당 하 는 구성원 변 수 를 대리 로 해 야 합 니 다.이런 방식 은 혼합 유형 이 비교적 많은 상황 에서 코드 량 이 급속히 증가 할 것 이다.
15.15.3 장식 기 모드 사용
장식 기 모드 는 레이 어 링 대상 을 사용 하여 하나의 대상 에 동적 으로 투명 하 게 책임 을 추가 합 니 다.장식 기 는 최초의 대상 주위 에 포 장 된 모든 대상 이 같은 기본 인 터 페 이 스 를 가지 고 있 음 을 지정 합 니 다.어떤 사물 은 장식 할 수 있 고 다른 종 류 를 장식 할 수 있 는 대상 의 주변 에 포장 함으로써 기능 을 층 으로 나 눌 수 있다.이 때문에 장식 기 에 대한 사용 은 투명 하 다.대상 이 장식 되 었 든 안 되 었 든 대상 에 게 보 낼 수 있 는 공공 메시지 집합 을 가지 고 있다.장식 류 에 도 새로운 방법 을 추가 할 수 있 지만 제한 을 받는다.장식 기 는 조합 과 형식화 구조(장식 가능 물/장식 기 차원 구조)를 사용 하여 이 루어 진 것 이 고 혼합 형 은 계승 을 바탕 으로 한다.따라서 매개 변수 화 유형 을 바탕 으로 하 는 혼합 형 을 일종 의 범 형 장식 기 체제 로 볼 수 있 고 이 체 제 는 장식 기 디자인 모델 의 계승 구 조 를 필요 로 하지 않 는 다.
package com.mzm.chapter15;

import java.util.Date;

/**
 *      
 *       ,            ,               
 * Created by     on 2018/1/14.
 */
public class Decoration {

    public static void main(String[] args) {
        TimeStamped2 t = new TimeStamped2(new Basic2());
        TimeStamped2 t2 = new TimeStamped2(new SerialNumbered2(new Basic2()));
        //t2 TimeStamped2  ,   getSerialNumber()  
        //t2.getSerialNumber();
        SerialNumbered2 s = new SerialNumbered2(new Basic2());
        SerialNumbered2 s2 = new SerialNumbered2(new TimeStamped2(new Basic2()));
        //s2 SerialNumbered2  ,   getStamp()  
        //s2.getStamp();
    }
}

/**
 *    
 */
class Basic2 {

    private String value;

    public void set(String val) {
        value = val;
    }

    public String get() {
        return value;
    }
}

/**
 *    
 */
class Decorator extends Basic2 {

    protected Basic2 basic2;

    public Decorator(Basic2 basic2) {
        this.basic2 = basic2;
    }

    public void set(String val) {
        basic2.set(val);
    }

    public String get() {
        return basic2.get();
    }
}

/**
 *    
 */
class TimeStamped2 extends Decorator {

    private final long timeStamp;

    public TimeStamped2(Basic2 basic2) {
        super(basic2);
        timeStamp = new Date().getTime();
    }

    public long getStamp() {
        return timeStamp;
    }
}

/**
 *    
 */
class SerialNumbered2 extends Decorator {

    private static long counter = 1;
    private final long serialNumber = counter++;

    public SerialNumbered2(Basic2 basic2) {
        super(basic2);
    }

    public long getSerialNumber() {
        return serialNumber;
    }
}

15.15.4 동적 에이전트 와 혼합
동적 에이 전 트 를 사용 하여 장식 기보 다 혼합 모델 에 더 가 까 운 메커니즘 을 만 들 수 있 습 니 다.동적 에이 전 트 를 사용 하면 클래스 의 동적 유형 은 이미 혼 입 된 조합 유형 이 될 것 입 니 다.
package com.mzm.chapter15;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;


/**
 * 
 */
public class DynamicProxyMixin {

    public static void main(String[] args) {
        Object mixin = MixinProxy.newInstance(
                new TwoTuple(new BasicImp(), Basic.class),
                new TwoTuple(new TimeStampedImp(), TimeStamped.class),
                new TwoTuple(new SerialNumberImp(), SerialNumbered.class)
        );
        Basic b = (Basic) mixin;
        TimeStamped t = (TimeStamped) mixin;
        SerialNumbered s = (SerialNumbered) mixin;
        b.set("Hello");
        System.out.println(b.get());
        System.out.println(t.getStamp());
        System.out.println(s.getSerialNumber());
    }
}

class MixinProxy implements InvocationHandler {

    Map delegateByMethod;

    @SuppressWarnings("unchecked")
    public MixinProxy(TwoTuple>... pairs) {
        delegateByMethod = new HashMap<>();
        for(TwoTuple> pair : pairs) {
            for(Method method : pair.second.getMethods()) {
                String methodName = method.getName();
                if(!delegateByMethod.containsKey(methodName)) {
                    delegateByMethod.put(methodName, pair.first);
                }
            }
        }
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        String methodName = method.getName();
        Object delegate = delegateByMethod.get(methodName);
        return method.invoke(delegate, args);

    }

    public static Object newInstance(TwoTuple... pairs) {
        Class[] interfaces = new Class[pairs.length];
        for(int i = 0; i < pairs.length; i++) {
            interfaces[i] = (Class) pairs[i].second;
        }
        ClassLoader cl = pairs[0].first.getClass().getClassLoader();
        return Proxy.newProxyInstance(cl, interfaces, new MixinProxy(pairs));
    }
}

15.16 잠재 유형 메커니즘
잠재 적 유형 체제(구조 화 유형 체제/오리 유형 체제)는 이러한 유형 체 제 를 가 진 언어 는 특정한 유형 이나 인터페이스 가 아니 라 특정한 방법 부분 만 실현 하도록 요구한다.이러한 유형의 메커니즘 을 가 진 언어 는 전형 적 으로 Python 과 C++예 가 있다.Python:
class Dog(Object):
    def speak(self):
        print("Arf!")
    def sit(self):
        print("Sitting")
    def reproduce(self):
        pass

class Robot(Object):
    def speak(self):
        print("Click!")
    def sit(self):
        print("Clank!")
    def oilChange(self):
        pass

def perform(anything):
    anything.speak()
    anything.sit()

if __name__ == '__main__':
    a = Dog()
    b = Robot()
    perform(a)
    perform(b)

perform()함 수 는 잠재 적 인 인 터 페 이 스 를 포함 하고 있 지만 명시 적 으로 설명 할 필요 가 없습니다.분명히 대상 이 speak()와 sit()두 가지 방법 을 실현 하면 perform()함수 에 들 어 갈 수 있다.자바 는 잠재 적 인 형식 체 제 를 지원 하지 않 기 때문에 위의 코드 를 자바 버 전 으로 변환 하면 다음 과 같 습 니 다.
package com.mzm.chapter15;

/**
 * 
 */
public interface Performs {

    void speak();
    void sit();

}
package com.mzm.chapter15;

import com.mzm.chapter14.Dog;

/**
 * 
 */
public class DogsAndRobots {

    public static void main(String[] args) {
        PerformingDog d = new PerformingDog();
        Robot r = new Robot();
        Communicate.perform(d);
        Communicate.perform(r);
    }
}


class PerformingDog extends Dog implements Performs {

    @Override
    public void speak() {
        System.out.println("Woof!");
    }

    @Override
    public void sit() {
        System.out.println("Sitting");
    }

    public void reproduce() {

    }
}

class Robot implements Performs {

    @Override
    public void speak() {
        System.out.println("Click!");
    }

    @Override
    public void sit() {
        System.out.println("Clank!");
    }

    public void oilChange() {

    }
}

class Communicate {

    public static  void perform(T performer) {
        performer.speak();
        performer.sit();
    }

}

15.17 잠재 적 유형 체제 에 대한 보상
15.17.1
반 사 를 통 해 자바 에서 잠재 적 인 유형 체 제 를 실현 할 수 있다.
package com.mzm.chapter15;

import java.lang.reflect.Method;

/**
 * 
 */
public class LatentReflection {

    public static void main(String[] args) {
        CommunicateReflectively.perform(new SmartDog());
        CommunicateReflectively.perform(new Robot());
        CommunicateReflectively.perform(new Mime());
    }
}

class Mime {

    public void walkAgainstTheWind() {

    }

    public void sit() {
        System.out.println("Pretending to sit");
    }

    public void pushInvisibleWalls() {

    }

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

}

class SmartDog {

    public void speak() {
        System.out.println("Woof!");
    }

    public void sit() {
        System.out.println("Sitting");
    }

    public void reproduce() {

    }
}

class CommunicateReflectively {

    public static void perform(Object speaker) {

        Class> spkr = speaker.getClass();

        try {
            try {
                Method speak = spkr.getMethod("speak");
                speak.invoke(speaker);
            } catch (NoSuchMethodException e) {
                System.out.println(speaker + " cannot speak");
            }

            try {
                Method sit = spkr.getMethod("sit");
                sit.invoke(speaker);
            } catch (NoSuchMethodException e) {
                System.out.println(speaker + " cannot sit");
            }
        } catch (Exception e) {
            throw new RuntimeException(speaker.toString(), e);
        }
    }
}

15.17.2 한 방법 을 서열 에 적용 한다.
앞에서 반사 방식 을 이용 하여 잠재 적 인 유형 체 제 를 실현 하 였 으 나 모든 유형 검 사 를 운행 기간 으로 옮 겼 다.우 리 는 컴 파일 기간 유형 검사 와 잠재 적 유형 체 제 를 동시에 실현 할 수 있 기 를 바 랍 니 다.
package com.mzm.chapter15;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 
 */
public class Apply {

    /**
     *                 
     * @param seq   Iterable       ,         T    T       
     * @param f     
     * @param args       
     * @param             
     * @param        
     */
    public static extends Iterable extends T>> void apply(S seq, Method f, Object... args) {
        try {
            for(T t : seq) {
                f.invoke(t, args);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

class Shape {

    public void rotate() {
        System.out.println(this + " rotate");
    }

    public void resize(int newSize) {
        System.out.println(this + " resize " + newSize);
    }

}

class Square extends Shape {

}

class FilledList<T> extends ArrayList<T> {

    public FilledList(Class extends T> type, int size) {
        try {
            for(int i = 0; i < size; i++) {
                add(type.newInstance());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

class ApplyTest {

    public static void main(String[] args) throws Exception {
        List shapes = new ArrayList<>();
        for(int i = 0; i < 10; i++) {
            shapes.add(new Shape());
        }
        Apply.apply(shapes, Shape.class.getMethod("rotate"));
        Apply.apply(shapes, Shape.class.getMethod("resize", int.class), 5);

        List squares = new ArrayList<>();
        for(int i = 0; i < 10; i++) {
            squares.add(new Square());
        }
        Apply.apply(squares, Shape.class.getMethod("rotate"));
        Apply.apply(squares, Shape.class.getMethod("resize", int.class), 5);

        Apply.apply(new FilledList<>(Shape.class, 10), Shape.class.getMethod("rotate"));
        Apply.apply(new FilledList<>(Square.class, 10), Square.class.getMethod("rotate"));

        SimpleQueue shapeQ = new SimpleQueue<>();
        for(int i = 0; i < 5; i++) {
            shapeQ.add(new Shape());
            shapeQ.add(new Square());
        }
        Apply.apply(shapeQ, Shape.class.getMethod("rotate"));
    }
}

15.17.3 당신 이 우연히 정확 한 인 터 페 이 스 를 가지 지 않 았 을 때
package com.mzm.chapter15;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 
 */
public class Fill {

    /**
     *           
     *          Collection       
     *       Collection       , SimpleQueue,       
     * @param collection     ,     T
     * @param classToken T      Class  
     * @param size     
     * @param    
     */
    public static  void fill(Collection collection, Class extends T> classToken, int size) {

        for(int i = 0; i < size; i++) {
            try {
                collection.add(classToken.newInstance());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}

class Contract {

    private static long counter = 0;
    private final long id = counter++;

    public String toString() {
        return getClass().getName() + " " + id;
    }
}

class TitleTransfer extends Contract {

    public static void main(String[] args) {
        List contracts = new ArrayList<>();
        Fill.fill(contracts, Contract.class, 3);
        Fill.fill(contracts, TitleTransfer.class, 2);

        for(Contract c : contracts) {
            System.out.println(c);
        }

        SimpleQueue contractsQ = new SimpleQueue<>();
        //SimpleQueue          Collection  
        //Fill.fill(contractsQ, Contract.class, 3);
    }
}

Fill 류 의 fill()방법 은 Collection 인 터 페 이 스 를 실현 한 용기 대상 에 만 적용 되 며,이 인 터 페 이 스 를 실현 하지 못 한 용기 대상 에 대해 서 는 add()방법 이 있어 도 fill()방법 을 사용 할 수 없습니다.이 방법 은 콜 렉 션 의 계승 범위 에 사용 범 위 를 한정 하기 때문에 그렇게 일반화 되 지 않 는 다.그리고 잠재 적 인 유형 체 제 를 사용 하 는 매개 변수 화 유형 체 제 를 사용 해 야 진정 으로 일반화 할 수 있다.
15.17.4 어댑터 로 잠재 적 유형 메커니즘 모방
잠재 적 인 형식 체 제 는 실제로 필요 한 방법 을 포함 하 는 암시 적 인 인 터 페 이 스 를 만 들 었 습 니 다.이 인 터 페 이 스 를 손 으로 만 들 면 문 제 를 해결 할 수 있 습 니 다.기 존의 인터페이스 에서 코드 를 작성 하여 필요 한 인 터 페 이 스 를 만 드 는 것 은 어댑터 디자인 모델 의 전형 적 인 예 이다.
package com.mzm.chapter15;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 *             
 * 
 */
public class Fill2 {

    /**
     * Class     fill()  
     * @param addable   Addable       ,        T
     * @param classToken            Class  
     * @param size     
     * @param      
     */
    public static  void fill(Addable addable, Class extends T> classToken, int size) {
        for(int i = 0; i < size; i++) {
            try {
                addable.add(classToken.newInstance());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     *       fill()  
     * @param addable   Addable       ,        T
     * @param generator            Class  
     * @param size     
     * @param      
     */
    public static  void fill(Addable addable, Generator generator, int size) {
        for(int i = 0; i < size; i++) {
            addable.add(generator.next());
        }
    }
}

/**
 *                 ,      
 * @param 
 */
interface Addable {
    void add(T t);
}

/**
 *     , Collection      
 * @param 
 */
class AddableCollectionAdapter implements Addable {

    private Collection c;

    public AddableCollectionAdapter(Collection c) {
        this.c = c;
    }

    @Override
    public void add(T item) {
        c.add(item);
    }
}

/**
 *          
 */
class Adapter {

    public static  Addable collectionAdapter(Collection c) {
        return new AddableCollectionAdapter<>(c);
    }
}

/**
 *   SimpleQueue ,    Addable  
 * @param 
 */
class AddableSimpleQueue extends SimpleQueue implements Addable {

    public void add(T item) {
        super.add(item);
    }
}

class Fill2Test {

    public static void main(String[] args) {

        //Collection    
        List carrier = new ArrayList<>();
        Fill2.fill(new AddableCollectionAdapter<>(carrier), Coffee.class, 3);

        Fill2.fill(Adapter.collectionAdapter(carrier), Latte.class, 2);

        for(Coffee c : carrier) {
            System.out.println(c);
        }

        System.out.println("----------------------------------------------");

        //      AddableSimpleQueue
        AddableSimpleQueue coffeeQ = new AddableSimpleQueue<>();
        Fill2.fill(coffeeQ, Mocha.class, 4);
        Fill2.fill(coffeeQ, Latte.class, 1);
        for(Coffee c : coffeeQ) {
            System.out.println(c);
        }
    }
}

하지만 어댑터 를 사용 하 는 것 은 추가 적 인 절차 다.
15.18 함수 대상 을 전략 으로 사용 합 니 다.
package com.mzm.chapter15;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;


/**
 *         
 * 
 */
public class Functional {

    /**
     * reduce  
     * @param seq       
     * @param combiner          
     * @param        
     * @return            combiner         
     */
    public static  T reduce(Iterable seq, Combiner combiner) {
        Iterator it = seq.iterator();
        if(it.hasNext()) {
            T result = it.next();
            while(it.hasNext()) {
                result = combiner.combine(result, it.next());
            }
            return result;
        }
        return null;
    }

    /**
     * foreach  
     * @param seq      
     * @param func              
     * @param        
     * @return     
     */
    public static  Collector forEach(Iterable seq, Collector func) {
        for(T t : seq) {
            func.function(t);
        }
        return func;
    }

    /**
     * transform  
     * @param seq       
     * @param func     , T       R    
     * @param       
     * @param       
     * @return       T           R   
     */
    public static  List transform(Iterable seq, UnaryFunction func) {
        List result = new ArrayList<>();
        for(T t : seq) {
            result.add(func.function(t));
        }
        return result;
    }

    /**
     * filter  
     * @param seq       
     * @param pred       ,         true false
     * @param         
     * @return                ,         
     */
    public static  List filter(Iterable seq, UnaryPredicate pred) {
        List result = new ArrayList<>();
        for(T t : seq) {
            if(pred.test(t)) {
                result.add(t);
            }
        }
        return result;
    }

    /**
     *        
     */
    static class IntegerAdder implements Combiner {

        @Override
        public Integer combine(Integer x, Integer y) {
            return x + y;
        }

    }

    /**
     *        
     */
    static class IntegerSubtracter implements Combiner {

        @Override
        public Integer combine(Integer x, Integer y) {
            return x - y;
        }

    }

    /**
     *          
     */
    static class BigDecimalAdder implements Combiner {

        @Override
        public BigDecimal combine(BigDecimal x, BigDecimal y) {
            return x.add(y);
        }

    }

    /**
     *         
     */
    static class BigIntegerAdder implements Combiner {

        @Override
        public BigInteger combine(BigInteger x, BigInteger y) {
            return x.add(y);
        }
    }

    /**
     *         
     */
    static class AtomicLongAdder implements Combiner {

        @Override
        public AtomicLong combine(AtomicLong x, AtomicLong y) {
            return new AtomicLong(x.addAndGet(y.get()));
        }

    }

    /**
     *                  (ulp)
     */
    static class BigDecimalUlp implements UnaryFunction {

        @Override
        public BigDecimal function(BigDecimal x) {
            return x.ulp();
        }

    }

    /**
     *     
     * @param    Comparable     
     */
    static class GreaterThan> implements UnaryPredicate{

        private T bound;

        public GreaterThan(T bound) {
            this.bound = bound;
        }

        @Override
        public boolean test(T x) {
            return x.compareTo(bound) > 0;
        }

    }

    /**
     *              ,        
     */
    static class MultiplyingIntegerCollector implements Collector {

        private Integer val = 1;

        @Override
        public Integer function(Integer x) {
            val *= x;
            return val;
        }

        @Override
        public Integer result() {
            return val;
        }
    }

    public static void main(String[] args) {
        List li = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
        Integer result = reduce(li, new IntegerAdder());
        System.out.println(result);

        result = reduce(li, new IntegerSubtracter());
        System.out.println(result);

        System.out.println(filter(li, new GreaterThan<>(4)));

        System.out.println(forEach(li, new MultiplyingIntegerCollector()).result());

        System.out.println(forEach(filter(li, new GreaterThan<>(4)), new MultiplyingIntegerCollector()).result());

        MathContext mc = new MathContext(7);
        List lbd = Arrays.asList(
                new BigDecimal(1.1, mc),
                new BigDecimal(2.2, mc),
                new BigDecimal(3.3, mc),
                new BigDecimal(4.4, mc)
        );
        BigDecimal rbd = reduce(lbd, new BigDecimalAdder());
        System.out.println(rbd);

        System.out.println(filter(lbd, new GreaterThan<>(new BigDecimal(3))));

        List lbi = new ArrayList<>();
        BigInteger bi = BigInteger.valueOf(11);
        for(int i = 0; i < 11; i++) {
            lbi.add(bi);
            bi = bi.nextProbablePrime();
        }
        System.out.println(lbi);

        BigInteger rbi = reduce(lbi, new BigIntegerAdder());
        System.out.println(rbi);
        System.out.println(rbi.isProbablePrime(5));

        List lal = Arrays.asList(
                new AtomicLong(11),
                new AtomicLong(47),
                new AtomicLong(74),
                new AtomicLong(133)
        );
        AtomicLong ral = reduce(lal, new AtomicLongAdder());
        System.out.println(ral);

        System.out.println(transform(lbd, new BigDecimalUlp()));
    }
}

/**
 *           ,     ,             
 * @param           
 */
interface Combiner {

    T combine(T x, T y);

}

/**
 *           ,     ,             
 * @param        
 * @param        
 */
interface UnaryFunction {

    R function(T x);

}

/**
 *                  
 * @param         
 */
interface Collector extends UnaryFunction {

    T result();

}

/**
 *             ,     ,               
 * @param 
 */
interface UnaryPredicate {

    boolean test(T x);

}

여기 서 자바 를 사용 하여 함수 식 프로 그래 밍 을 실현 합 니 다.그 중에서 Combiner,Unary Function,Collector 와 Unary Predicate 는 다른 언어 에서 이른바 잠재 적 인 유형 체 제 를 사용 하여 실현 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기