过于复杂的设计模式

lbsnaicq  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(370)

我试图用设计模式解决一个设计问题。既然我已经掌握了基本知识,我很肯定我已经把它复杂化了很多。我似乎有多个空接口,我可能可以用一个不同的设计少。另外,我也不确定这个项目的未来开发者是否能轻松地解决这个问题。
我做了一个班级结构的模型。该示例简化为两种服务类型(cf baseanimalservice extensions),在项目中还有更多。还有更多的基本策略实现。
首先,我想区分catservice和dogservice的上下文。这是使用basestrategy类中的一个Map来完成的,该Map将baseanimalservice作为值来启用cat/dogservice之间的多态性。根据在dog/catstrategy中实现的basestrategy的通用类型,使用不同的configurationmap,而configurationmap又根据条件的类型加载dog/catservice的一个或另一个实现。配置Map在spring.xml文件中定义。
由于dog/catservice都实现了一个额外的接口,参见someothercat/dogservice,这是我的设计之外的,dog/catservice也都有空接口。someothercatservice和someotherdogservice不相关,也不可编辑,所以我不能多态地使用它们,这就是base/cat/dogservice接口的原因。
我考虑过让basestrategy成为一个strategyfactory,它返回一个cat/dogstrategy,它反过来检查baseanimalservice要使用的标准的类型。但是由于这两种策略对它们的策略使用相同的逻辑,这意味着我必须创建另一个基类。
你怎么认为?对于这个问题有什么更好的设计建议吗?或者对现在的有什么改进?

class BaseStrategy<T extends BaseAnimalService> {

    private ContextService contextService;
    private Map<String, BaseAnimalService> configurationMap;

    T getService() {
        return configurationMap.get(contextService.getCurrentContext());
    }
}

interface BaseAnimalService {
    //empty
}

interface DogService extends BaseAnimalService {
    //empty
}

interface CatService extends BaseAnimalService {
    //empty
}

class DogStrategy extends BaseStrategy<DogService> {
    //empty
}

class CatStrategy extends BaseStrategy<CatService> {
    //empty
}

class BritishShortHairServiceImpl implements CatService, SomeOtherCatService {
    @Override //source: SomeOtherCatService, same for other implementations below
    void pur() {
        //pur
    }
}

class LionServiceImpl implements CatService, SomeOtherCatService {
    @Override
    void pur() {
        //pur
    }
}

class PitBullServiceImpl implements DogService, SomeOtherDogService {
    @Override
    void wagTail() {
        //wag tail
    }
}

class ChihuahuaServiceImpl implements DogService, SomeOtherDogService {
    @Override
    void wagTail() {
        //wag tail
    }
}

class CatPerson {
    private BaseStrategy<CatService> catStrategy;

    void pet() {
        catStrategy.getService().pur();
    }
}

class DogPerson {
    private BaseStrategy<DogService> dogStrategy;

    void feed() {
        dogStrategy.getService().wagTail();
    }
}

相关spring.xml片段:

<bean id="baseStrategy" abstract="true"
          class="com.animals.services.BaseStrategy">
        <property name="contextService" ref="contextService"/>
    </bean>

<bean id="catServiceStrategy"
          class="com.animals.services.CatStrategyImpl"
          parent="baseStrategy">
        <property name="strategyConfigurationMap">
            <map>
                <entry key="CONTEXT1" value-ref="britishShortHairService"/>
                <entry key="CONTEXT2" value-ref="lionService"/>
            </map>
        </property>
    </bean>

<bean id="dogServiceStrategy"
          class="com.animals.services.DogStrategyImpl"
          parent="baseStrategy">
        <property name="strategyConfigurationMap">
            <map>
                <entry key="CONTEXT1" value-ref="pitbullService"/>
                <entry key="CONTEXT2" value-ref="chihuahuaService"/>
            </map>
        </property>
    </bean>
guz6ccqo

guz6ccqo1#

我不熟悉spring或它的上下文服务模型,所以我从一个通用的、独立于语言的oopAngular 来处理这个问题。
在我看来,您需要考虑通过构造函数传递配置的方法(依赖注入),而不是基于Map进行切换。你需要更多的“has a”关系(合成)和更少的“is a”关系(继承)。
AnimalService 可以将动物对象作为构造函数的参数。我们可以说 AnimalFeedbackBehavior 必须包括 positiveFeedback() , neutralFeedback() ,和 negativeFeedback() --但这些方法的实施方式因动物而异。一 Cat 会吗 purr() 为了回应积极的互动 Dog 会吗 wagTail() .
AnimalOwner 可以 feed() 任何动物和扳机 AnimalFeedbackBehavior.positiveFeedback() . 这个 AnimalOwner 不需要知道这种行为在幕后做了什么。它甚至不需要知道它有什么种类的动物。它只需要知道这个方法是存在的。

interface AnimalFeedbackBehavior {
    positiveFeedback(): void;
    neutralFeedback(): void;
    negativeFeedback(): void;
}

class AnimalOwner {
    private animal: AnimalFeedbackBehavior;

    // pass animal instance to the constructor
    constructor( animal: AnimalFeedbackBehavior) {
        this.animal = animal;
    }

    // trigger positive feedback when feeding
    feed() {
        this.animal.positiveFeedback();
    }
}

class Cat implements AnimalFeedbackBehavior {
    purr() {
        //do something
    }

    positiveFeedback() {
        this.purr();
    }

    /* ... rest of class ... */
}

typescriptPlayground链接
这里我们假设 feed 总是积极的互动。但是如果我们想让不同的动物对相同的相互作用有不同的React呢? chase() 可能对一段时间是积极的 Dog 但对于一个 Cat . 阿娜ïve方法是根据Map切换反馈。但理想的设计允许最大限度地抽象 AnimalOwner 不需要知道动物的种类。
让我们尝试一个完全不同的设置。
如果你处理的是一小部分行为,我们可以要求动物对每种行为都有React,而不是积极/中立/消极。

interface AnimalBehavior {
    feedResponse(): void;
    chaseResponse(): void;
}

但这可能会很快变得笨拙。我们可以定义一种有 respond 方法,该方法响应某种泛型操作对象。在实现中,它可以对操作做出响应,也可以忽略它。
这种设置还使得多个重写行为的组合更加直观,因为我们可以通过一系列 respond 直到有人处理它。我们想知道是否有回应,所以我们需要从 response 功能。如果基本上 void 然后我们可以返回一个 boolean 旗子那是 true 如果它有React。如果响应应返回一个值,则返回该值或 undefined .

interface Action {
    type: string;
}

// we may want to attach some sort of data
interface ActionWithData<T> extends Action {
    type: string;
    data: T;
}

interface AnimalBehavior {
    respond( action: Action ): string | undefined;
}

class Animal implements AnimalBehavior {
    // an animal has an array of behavior responders
    // as written, the earlier behaviors in the array override later ones
    private behaviors: AnimalBehavior[];

    // can instantiate an animal with multiple behaviors
    constructor( behaviors: AnimalBehavior[] = [] ) {
        this.behaviors = behaviors;
    }

    // can also add behaviors after the fact
    public addOverride( behavior: AnimalBehavior ) {
        this.behaviors = [behavior, ...this.behaviors];
    }

    // loop through behaviors until one responds
    public respond (action: Action): string | undefined {
        for ( let element of this.behaviors ) {
            // could be a response or might be undefined
            const response = element.respond(action);
            if ( response ) {
                return response;
            }
        }
        // could do something here if no behaviors responded
        return undefined;
    }
}

class AnimalOwner {
    private animal: AnimalBehavior;

    // pass animal instance to the constructor
    constructor( animal: AnimalBehavior) {
        this.animal = animal;
    }

    // animal can respond to the feed action, or not
    feed(): string | undefined {
        return this.animal.respond({type: 'feed'});
    }

    chase(): string | undefined {
        return this.animal.respond({ type: 'chase' });
    }
}

这些实现目前感觉有些草率。现在他们都没用 this 所以使用 class . 但我想告诉你:

class DogBehavior implements AnimalBehavior {
    respond(action: Action): string | undefined {
        switch (action.type) {
            case 'feed':
                return "Wag Tail";
            case 'chase':

                return "Run Around";
            default:
                return undefined;
        }
    }
}

class PuppyBehavior implements AnimalBehavior {
    respond(action: Action): string | undefined {
        switch (action.type) {
            case 'feed':
                return "Jump";
            default:
                return undefined;
        }
    }
}

class ChihuahuaBehavior implements AnimalBehavior {
    respond(action: Action): string | undefined {
        switch (action.type) {
            case 'feed':
                return "Yip";
            default:
                return undefined;
        }
    }
}

两个 Animal 构成与个体行为实现 AnimalBehavior ,所以 AnimalOwner 我可以休息一下 DogBehavior 直接或需要 Animal 由一个 DogBehavior 以及其他一些行为。

const owner1 = new AnimalOwner(new DogBehavior());
let res = owner1.feed(); // is "Wag Tail"

顺序很重要。如果我们有一只吉娃娃小狗,我们需要决定 ChihuahuaBehavior 覆盖 PuppyBehavior 反之亦然。

// prioritizes puppy
const owner2 = new AnimalOwner(new Animal([new PuppyBehavior(), new ChihuahuaBehavior(), new DogBehavior()]));
res = owner2.feed(); // is "Jump" from PuppyBehavior
res = owner2.chase(); // is "Run Around" from DogBehavior because not overwritten

// prioritizes chihuahua
const owner3 = new AnimalOwner(new Animal([new ChihuahuaBehavior(), new PuppyBehavior(), new DogBehavior()]));
res = owner3.feed(); // is "Yip" from ChihuahuaBehavior

typescriptPlayground链接

相关问题