gpt4 book ai didi

oop - 作文,我不太明白?

转载 作者:行者123 更新时间:2023-12-04 23:21:18 25 4
gpt4 key购买 nike

引用以下链接:

http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html?page=2

The composition approach to code reuse provides stronger encapsulation than inheritance, because a change to a back-end class needn't break any code that relies only on the front-end class. For example, changing the return type of Fruit's peel() method from the previous example doesn't force a change in Apple's interface and therefore needn't break Example2's code.

当然,如果您更改 peel() 的返回类型(参见下面的代码),这意味着 getPeelCount() 将无法返回 int 还有吗?难道你不必更改接口(interface),否则会出现编译器错误吗?

class Fruit {

// Return int number of pieces of peel that
// resulted from the peeling activity.
public int peel() {

System.out.println("Peeling is appealing.");
return 1;
}
}

class Apple {

private Fruit fruit = new Fruit();

public int peel() {
return fruit.peel();
}
}

class Example2 {

public static void main(String[] args) {

Apple apple = new Apple();
int pieces = apple.peel();
}
}

最佳答案

有了composition,改变类Fruit并不一定需要改变Apple,例如,让我们改变剥离 以返回 double :

class Fruit {

// Return String number of pieces of peel that
// resulted from the peeling activity.
public double peel() {

System.out.println("Peeling is appealing.");
return 1.0;
}
}

现在,类 Apple 将警告精度丢失,但您的 Example2 类会很好,因为组合更“松散”并且发生变化在组合元素中不会破坏组合类 API。在我们的示例中,只需像这样更改 Apple :

class Apple {

private Fruit fruit = new Fruit();

public int peel() {
return (int) fruit.peel();
}
}

而如果 Apple inherited from Fruit(class Apple extends Fruit),你不仅会得到一个关于不兼容的返回类型方法的错误,但在 Example2 中也会出现编译错误。

** 编辑 **

让我们重新开始,给出一个组合继承的“真实世界”示例。请注意,合成不限于此示例,还有更多可以使用该模式的用例。

示例 1:继承

应用程序将形状绘制到 Canvas 中。应用程序不需要知道它必须绘制哪些形状,并且实现在于继承抽象类或接口(interface)的具体类。但是,应用程序知道它可以创建什么以及可以创建多少种不同的具体形状,因此添加或删除具体形状需要在应用程序中进行一些重构。

interface Shape {
public void draw(Graphics g);
}

class Box implement Shape {
...
public void draw(Graphics g) { ... }
}

class Ellipse implements Shape {
...
public void draw(Graphics g) { ... }
}

class ShapeCanvas extends JPanel {
private List<Shape> shapes;
...
protected void paintComponent(Graphics g) {
for (Shape s : shapes) { s.draw(g); }
}
}

示例 2:组合

应用程序正在使用 native 库来处理某些数据。实际的库实现可能是已知的,也可能是未知的,并且将来可能会或可能不会改变。因此创建了一个公共(public)接口(interface),并在运行时确定了实际的实现。例如:

interface DataProcessorAdapter {
...
public Result process(Data data);
}

class DataProcessor {
private DataProcessorAdapter adapter;
public DataProcessor() {
try {
adapter = DataProcessorManager.createAdapter();
} catch (Exception e) {
throw new RuntimeException("Could not load processor adapter");
}
}
public Object process(Object data) {
return adapter.process(data);
}
}

static class DataProcessorManager {
static public DataProcessorAdapter createAdapter() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
String adapterClassName = /* load class name from resource bundle */;

Class<?> adapterClass = Class.forName(adapterClassName);
DataProcessorAdapter adapter = (DataProcessorAdapter) adapterClass.newInstance();
//...

return adapter;
}
}

因此,如您所见,组合可能比继承提供一些优势,因为它允许代码具有更大的灵 active 。它允许应用程序拥有可靠的 API,而底层实现在其生命周期内仍可能发生变化。如果使用得当,组合物可以显着降低维护成本。

例如,当使用 JUnit 为 示例 2 实现测试用例时,您可能希望使用虚拟处理器并设置 DataProcessorManager 以返回此类适配器,同时使用生产中的“真实”适配器(可能取决于操作系统),而无需更改应用程序源代码。使用继承,你很可能会修改一些东西,或者可能会编写更多的初始化测试代码。

如您所见,compisitioninheritance 在许多方面都不同,并且并不优于其他方面;每个都取决于手头的问题。你甚至可以混合继承和组合,例如:

static interface IShape {
public void draw(Graphics g);
}

static class Shape implements IShape {
private IShape shape;
public Shape(Class<? extends IShape> shape) throws InstantiationException, IllegalAccessException {
this.shape = (IShape) shape.newInstance();
}
public void draw(Graphics g) {
System.out.print("Drawing shape : ");
shape.draw(g);
}
}

static class Box implements IShape {
@Override
public void draw(Graphics g) {
System.out.println("Box");
}
}

static class Ellipse implements IShape {
@Override
public void draw(Graphics g) {
System.out.println("Ellipse");
}
}

static public void main(String...args) throws InstantiationException, IllegalAccessException {
IShape box = new Shape(Box.class);
IShape ellipse = new Shape(Ellipse.class);

box.draw(null);
ellipse.draw(null);
}

当然,最后一个例子并不干净(意思是,避免它),但它展示了如何使用组合

底线是,DataProcessorShape 这两个示例都是“实体”类,它们的 API 不应更改。但是,适配器类可能会更改,如果发生更改,这些更改只会影响其组成容器,因此将维护限制在仅这些类而不是整个应用程序上,这与 示例 1 的任何更改相反需要在整个应用程序中进行更多更改。这完全取决于您的应用程序需要有多灵活。

关于oop - 作文,我不太明白?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9559291/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com