2015年1月11日日曜日

開発環境

Head First Object-Oriented Analysis and Design: A Brain Friendly Guide to OOA&D (Brett McLaughlin (著)、 Gary Pollice (著)、 David West (著) 、 O'Reilly Media)のChapter 5. Good Design = Flexible Software: Give Your Software a 30-minute Workout、THE GREAT EASE-OF-CHANGE CHALLENGE(No. 3385)をC言語で考えてみる。

THE GREAT EASE-OF-CHANGE CHALLENGE(No. 3385)

コード(BBEdit, Emacs)

find_instrument.c

#include "dict.h"
#include "instrument_spec.h"
#include "inventory.h"

static void initialize_inventory(inventory *in) {
  dictionary *properties = dictionary_new();
  dictionary_add(properties, "instrument_type", "guitar");
  dictionary_add(properties, "builder", "colllings");
  dictionary_add(properties, "model", "cj");
  dictionary_add(properties, "type", "acoustic");
  dictionary_add(properties, "top wood", "indian posewood");
  dictionary_add(properties, "back_wood", "sitfas");
  instrument_spec *spec = instrument_spec_new(properties);
  inventory_add_instrument(in, "11277", 3999.95, spec);
  instrument_spec_free(spec);
  dictionary_free(properties);
  
  properties = dictionary_new();
  dictionary_add(properties, "instrument_type", "guitar");
  dictionary_add(properties, "builder", "martin");
  dictionary_add(properties, "model", "D");
  dictionary_add(properties, "type", "acoustic");
  dictionary_add(properties, "num_strings", "6");
  dictionary_add(properties, "top_wood", "adirondack");
  dictionary_add(properties, "back_wood", "mahogany");
  spec = instrument_spec_new(properties);
  dictionary_free(properties);
  inventory_add_instrument(in, "122784", 5495.95, spec);
  instrument_spec_free(spec);

  properties = dictionary_new();
  dictionary_add(properties, "instrument_type", "guitar");
  dictionary_add(properties, "builder", "fender");
  dictionary_add(properties, "model", "stratocastor");
  dictionary_add(properties, "type", "electric");
  dictionary_add(properties, "num_strings", "6");
  dictionary_add(properties, "top_wood", "alder");
  dictionary_add(properties, "back_wood", "alder");
  spec = instrument_spec_new(properties);
  dictionary_free(properties);
  inventory_add_instrument(in, "V95693", 1499.95, spec);
  instrument_spec_free(spec);

  properties = dictionary_new();
  dictionary_add(properties, "instrument_type", "guitar");
  dictionary_add(properties, "builder", "fender");
  dictionary_add(properties, "model", "stratocastor");
  dictionary_add(properties, "type", "electric");
  dictionary_add(properties, "num_strings", "6");
  dictionary_add(properties, "top_wood", "alder");
  dictionary_add(properties, "back_wood", "alder");
  spec = instrument_spec_new(properties);
  dictionary_free(properties);
  inventory_add_instrument(in, "V9512", 1549.95, spec);
  instrument_spec_free(spec);

  properties = dictionary_new();
  dictionary_add(properties, "instrument_type", "guitar");
  dictionary_add(properties, "builder", "gibson");
  dictionary_add(properties, "model", "5G");
  dictionary_add(properties, "type", "electric");
  dictionary_add(properties, "num_strings", "6");
  dictionary_add(properties, "top_wood", "mahogany");
  dictionary_add(properties, "back_wood", "mahogany");
  spec = instrument_spec_new(properties);
  dictionary_free(properties);
  inventory_add_instrument(in, "82765501", 1890.95, spec);
  instrument_spec_free(spec);

  properties = dictionary_new();
  dictionary_add(properties, "instrument_type", "guitar");
  dictionary_add(properties, "builder", "gibson");
  dictionary_add(properties, "model", "Les Paul");
  dictionary_add(properties, "type", "electric");
  dictionary_add(properties, "num_strings", "6");
  dictionary_add(properties, "top_wood", "maple");
  dictionary_add(properties, "back_wood", "maple");
  spec = instrument_spec_new(properties);
  inventory_add_instrument(in, "70108276", 52295.95, spec);
  instrument_spec_free(spec);
  dictionary_free(properties);

  properties = dictionary_new();
  dictionary_add(properties, "instrument_type", "mandolin");
  dictionary_add(properties, "builder", "gibson");
  dictionary_add(properties, "model", "F5-G");
  dictionary_add(properties, "type", "acoustic");
  dictionary_add(properties, "top_wood", "maple");
  dictionary_add(properties, "back_wood", "maple");
  spec = instrument_spec_new(properties);
  dictionary_free(properties);
  inventory_add_instrument(in, "9019920", 5495.99, spec);
  instrument_spec_free(spec);

  properties = dictionary_new();
  dictionary_add(properties, "instrument_type", "banjo");
  dictionary_add(properties, "builder", "gibson");
  dictionary_add(properties, "model", "RB-3");
  dictionary_add(properties, "type", "acoustic");
  dictionary_add(properties, "num_strings", "5");
  dictionary_add(properties, "back_wood", "maple");
  spec = instrument_spec_new(properties);
  dictionary_free(properties);
  inventory_add_instrument(in, "8900231", 2945.95, spec);
  instrument_spec_free(spec);
}
                                 
int main() {
  inventory *inv = inventory_new();
  initialize_inventory(inv);
  dictionary *properties = dictionary_new();
  dictionary_add(properties, "builder", "gibson");
  dictionary_add(properties, "back_wood", "maple");
  instrument_spec *client_spec = instrument_spec_new(properties);
  
  instrument** instruments = inventory_search(inv, client_spec);
  if (instruments[0] != NULL) {
    printf("You might like these instruments:\n");
    for (int i = 0; instruments[i] != NULL; i++) {
      printf("%d\n", i + 1);
      instrument_spec_print(instruments[i]->spec);
      instrument_print(instruments[i]);
    }
  } else
    printf("Sorry, we have nothing for you.\n");
}

instrument_spec.h.

#pragma once
#include "dict.h"

typedef struct instrument_spec {
  dictionary* properties;
  void* (*get_property)(struct instrument_spec*, char const *);
  int (*matches)(struct instrument_spec*, struct instrument_spec*);
} instrument_spec;

instrument_spec *instrument_spec_new(dictionary *in);
instrument_spec* instrument_spec_copy(instrument_spec *in);
void instrument_spec_free(instrument_spec *in);
void* instrument_spec_get_property(instrument_spec *in, char const * name);
int instrument_spec_matches(instrument_spec *in, instrument_spec *other);
void instrument_spec_print(instrument_spec *in);

instrument_spec.c.

#include <stdlib.h>
#include "instrument_spec.h"

instrument_spec *instrument_spec_new(dictionary *in) {
  instrument_spec *out = malloc(sizeof(instrument_spec));
  *out = (instrument_spec){.properties=dictionary_copy(in)};
  return out;
}

instrument_spec* instrument_spec_copy(instrument_spec *in) {
  instrument_spec *out = instrument_spec_new(in->properties);
  return out;
}

void instrument_spec_free(instrument_spec *in) {
  dictionary_free(in->properties);
  free(in);
}

void* instrument_spec_get_property(instrument_spec *in, char const * name) {
  if (in->get_property) {
    return in->get_property(in, name);    
  }
  return dictionary_find((dictionary const *)&(in->properties), name);
}

int instrument_spec_matches(instrument_spec *in, instrument_spec *other) {  
  dictionary* kv = other->properties;
  keyval** pairs = kv->pairs;
  for (int i = 0; i < other->properties->length; i++) {    
    keyval* kv = pairs[i];
    char *key = kv->key;
    if (dictionary_find(in->properties, key) != dictionary_not_found &&
        strcmp(dictionary_find(in->properties, key), kv->value)) {
      return 0;
    }
  }
  return 1;
}

void instrument_spec_print(instrument_spec *in) {
  dictionary* kv = in->properties;
  keyval** pairs = kv->pairs;
  for (int i = 0; i < in->properties->length; i++) {
    char *key = pairs[i]->key;
    char *value = dictionary_find(in->properties, key);
    printf("%s: %s\n", key, value);
  }
}

inventory.h

#pragma once

#include "instrument.h"

typedef struct inventory {
  instrument **instruments;
  int length;
} inventory;

inventory* inventory_new();
void inventory_free(inventory *in);

void inventory_add_instrument(inventory *in, char *serial_number, double price,
                              instrument_spec* spec);

instrument** inventory_search(inventory *in, instrument_spec *spec);
  

inventory.c

#include "inventory.h"
#include "instrument.h"

inventory* inventory_new() {
  inventory* out = malloc(sizeof(inventory));
  *out = (inventory){.instruments=malloc(sizeof(instrument**)),.length=0};
  return out;
}

void inventory_free(inventory *in) {
  for (int i = 0; i < in->length; i++)
    instrument_free(in->instruments[i]);
  free(in);  
}

void inventory_add_instrument(inventory *in, char *serial_number, double price,
                              instrument_spec* spec) {
  instrument *inst = instrument_new(serial_number, price, spec);
  in->length++;
  in->instruments = realloc(in->instruments, sizeof(instrument*)*in->length);
  in->instruments[in->length - 1] = inst;
}

instrument** inventory_search(inventory *in, instrument_spec *spec) {
  instrument** out;
  int j = 0;
  for (int i = 0; i < in->length; i++) {
    if (instrument_spec_matches(spec, in->instruments[i]->spec)) {
      out = realloc(out, sizeof(instrument)*(j + 1));
      out[j] = in->instruments[i];
      j++;
    }
  }
  out = realloc(out, sizeof(instrument)*(j + 1));
  out[j] = NULL;
  return out;
}

instrument.h

#pragma once

#include "instrument_spec.h"

typedef struct instrument {
  char *serial_number;
  double price;
  instrument_spec *spec;
} instrument;

instrument* instrument_new(char *, double, instrument_spec*);
void instrument_free(instrument *in);

void instrument_print(instrument *in);

instrument.c

#include <stdlib.h>
#include "instrument.h"

instrument* instrument_new(char * serial_number, double price,
                           instrument_spec *spec) {
  instrument *out = malloc(sizeof(instrument));
  *out = (instrument){.serial_number=strdup(serial_number),.price=price,
                      .spec=instrument_spec_copy(spec)};
  return out;
}
                           
void instrument_free(instrument *in) {
  free(in->serial_number);
  free(in);
}

void instrument_print(instrument *in) {
  printf("serial number:%s price:%g\n", in->serial_number, in->price);
}

入出力結果(Terminal)

$ make &&./find_instrument
clang ...
You might like these instruments:
1
instrument_type: guitar
builder: gibson
model: Les Paul
type: electric
num_strings: 6
top_wood: maple
back_wood: maple
serial number:70108276 price:52295.9
2
instrument_type: mandolin
builder: gibson
model: F5-G
type: acoustic
top_wood: maple
back_wood: maple
serial number:9019920 price:5495.99
3
instrument_type: banjo
builder: gibson
model: RB-3
type: acoustic
num_strings: 5
back_wood: maple
serial number:8900231 price:2945.95
$

0 コメント:

コメントを投稿