设计模式

一、常量接口模式

在一个软件系统中会使用一些常量,一种流行的做法就是把相关的常量放在一个专门的常量接口中定义,例如:

public interface MyConstants {
    public static final double MATH_PI = 3.1415926;
    public static final double MATH_E = 2.71828;
 
}

以下Circle类需要访问以上MATH_PI常量,一种方式是采用直接访问方式,如下:

public class Circle {
    private double r;//半径
    public Circle(double r){
        this.r = r;
    }
    public double getCircumference(){
        return 2 * r * MyConstants.MATH_PI;
    }
}

在JDK1.5中引入了”import static“语句,它允许类A直接访问另一个接口B或类B中的静态常量,而不必指定接口B或类B的名字,而且类A无须实现接口B或者继承类B。如下:

import static com.FinalInterface.MyConstants.*;
public class Circle {
    private double r;//半径
    public Circle(double r){
        this.r = r;
    }
    public double getCircumference(){
        return 2 * r * MATH_PI;
    }
}

import static 语句既可以简化编程,又能防止Circle类继承并公开MyConstants中的静态常量。

二、标识类模式

动物饲养员给猫喂鱼,给狗喂骨头,给老虎喂鸡,给熊猫喂竹子,给马喂草,,这里的鱼、骨头、鸡、竹子、草都可以作为动物的食物,因此从中抽象出Food接口。

public interface Food()   //Food接口中没有任何内容

Food接口不包含任何方法,它仅仅表示一种抽象类型,所有实现该接口的类意味着可以作为食物,例如鱼类Fish实现了Food接口,因此它可以作为其他动物的食物

public class Fish extends Animal implments Food(...)

动物饲养员Feeder类的feed()方法的定义如下:

public void feed (Animal animal,Food food){...}

feed方法的food参数为Food类型,表示只能把可作为食物的对象喂给动物,以下程序表示试图给狗喂书,由于Book类没有实现Food接口,因此导致编译错误

Book book =new Book();
feeder.feed(dog,book);  //编译错误

如果把feed方法的food参数改为Object类型:

public void feed(Animal animal,Object food){...}

那么就无法借助java编译器来对传给feed方法的food参数进行语义上的约束,例如以下程序表示给狗喂一个字符串对象,java编译器会认为这是合法的

Object anyObject=new String("hello");
feeder.feed(dog,anyObject); //编译成功

Food接口被称为标识类型接口,这种接口没有任何方法,代表一种抽象类型,在JDK中,有如下两个典型的标识类型接口

① java.io.Serializable接口:实现该接口的类的实例可以被序列化

②java.io.Remote接口:实现该接口的类的实例可以作为远程对象

三、适配器模式

适配器是两个接口的中间过度,比如电脑必须要保证电压在15V,而电源的电压是220V,则需要一个适配器将220V转换成15V,因此适配器就是接口的转换作用。

interface Source{
    public int add(int a,int b);
}
class SourceImpl implements Source{
    public int add(int a,int b){
        return a+b;
    }
}
interface Target{
    public int addOne(int a);
}
class TargetImpl implements Target{
    private Source s ;
    public TargetImpl(Source s){
        this.s = s;
    }
    public int addOne(int a){
        return s.add(a,1);
    }
}
public class AdapterDemo{
    public static void main(String args[]){
        Source s = new SourceImpl();
        Target t = new TargetImpl(s);
        System.out.println("2+1="+t.addOne(2));
    }
}

四、定制服务模式

定制服务的模式也可应用到面向对象的软件开发领域。当一个系统能对外提供多种类型的服务时,一种方式是粗粒度的接口,把所有的服务放在一个接口中声明,这个接口臃肿庞大,所有的使用者都访问同一个接口。还有一种方式就是设计精粒度接口,对服务精心分类,把相关的一组服务放在一个接口中,通过对接口的继承,可以派生出新的接口,针对使用者的需求提供特定的接口

上表中的极速精英套餐SuperSpeedCombo和金融专网套餐FinanceCombo属于两种定制的服务接口,它们可以通过继承以上5个精粒度的接口而形成,这样的接口也称为复合接口。

服务接口定制好以后,接下来的问题是如何实现这些接口。为了提高代码的可重用性,类的粒度也应该尽可能小,所以首先为精粒度的接口提供实现类。

以下列出其中的一个服务实现类:

public class BroadbandServiceImpl implements BroadbandService{
    private int speed;//网速
    public BroadbandServiceImpl(int speed){
        this.speed = speed;
    }
    //连接网络
    public void connect(String username,String password){...}

    //断开网络
    public void disconnect(){...}
}

同上,将精粒度的接口一一创建实现类,得到精粒度的类。

那么对于SuperSpeedCombo 和 FinanceCombo 复合接口,如何实现它们呢?以 SuperSpeedCombo接口的实现类 SuperSpeedComboImpl为例,可以采用组合手段,复用 BroadbandService接口、VirusKillingService接口和MailboxService接口的实现类的程序代码。

那么什么是组合关系呢?在这再复习一下,所谓的组合和继承都是提高代码可重用性的手段,继承最大的弱点就是破坏封装,子类和父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性,而组合关系不会破坏封装,整体类与局部类之间松耦合,彼此相互独立。当然组合关系也有缺点:创建整体类的对象时需要创建所有局部类的对象,而继承关系在创建子类的对象时无须创建父类的对象。

比如要在SuperSpeedComboImpl采用组合手段加入宽带上网服务BroadbandService:

public class SuperSpeedComboImpl implements SuperSpeedCombo{
    private BroadbandServiceImpl BroadbandService;
    public SuperSpeedComboImpl(BroadbandServiceImpl BroadbandService){
        this.BroadbandService = BroadbandService;
    }
}

此外,对于极速精英套餐和金融专网套餐,都有付费方式和价格这些属性,可以把这些属性放到同一个Payment中,这符合构建精粒度的对象模型的原则,下面是Payment的源程序:

public class Payment{
    public static final String TYPE_PER_YEAR="按年付费";
    public static final String TYPE_PER_MONTH="按月付费";
    private String type;//付费方式
    private double price;//价格
    public Payment(String type, double price) {
        this.type = type;
        this.price = price;
    }
    //省略type属性和price属性的get/set方法
    ...
}

SuperSpeedComboImpl类的源程序如下:

public class SuperSpeedComboImpl implements SuperSpeedCombo{
    private BroadbandServiceImpl BroadbandService;
    private VirusKillingService virusKillingService;
    private MailboxService mailboxService;
    private Payment payment;
    public SuperSpeedComboImpl(BroadbandServiceImpl broadbandService, VirusKillingService virusKillingService,
            MailboxService mailboxService, Payment payment) {
        super();
        BroadbandService = broadbandService;
        this.virusKillingService = virusKillingService;
        this.mailboxService = mailboxService;
        this.payment = payment;
    }
    public BroadbandServiceImpl getBroadbandService() {
        return BroadbandService;
    }
    public void setBroadbandService(BroadbandServiceImpl broadbandService) {
        BroadbandService = broadbandService;
    }
    public VirusKillingService getVirusKillingService() {
        return virusKillingService;
    }
    public void setVirusKillingService(VirusKillingService virusKillingService) {
        this.virusKillingService = virusKillingService;
    }
    public MailboxService getMailboxService() {
        return mailboxService;
    }
    public void setMailboxService(MailboxService mailboxService) {
        this.mailboxService = mailboxService;
    }
    public Payment getPayment() {
        return payment;
    }
    public void setPayment(Payment payment) {
        this.payment = payment;
    }
}

下面创建一个极速精英套餐服务的一个实例:

//创建付费信息,按年付费,价格1555
Payment payment = new Payment(Payment.TYPE_PER_MONTH,1555);

//创建宽带上网服务,网速2Mbps
BroadbandService broadbandService = new BroadbandServiceImpl(2);

//创建邮箱服务,50MB容量
MailboxService mailboxService = new MialboxServiceImpl(50);

//创建在线杀毒服务
VirusKillingService virusKillingService = new VirusKillingServiceImpl();

//创建极速精英套餐服务
SuperSpeedCombo superSpeedCombo = 
    new SuperSpeedComboImpl(broadbandService,mailboxService,virusKillingService,payment);
原文地址:https://www.cnblogs.com/WJ-163/p/5578330.html